qvm-usb: always pass VM as object reference not a name

Make the API consistent.

QubesOS/qubes-issues#531
This commit is contained in:
Marek Marczykowski-Górecki 2016-06-02 02:44:38 +02:00
parent d67636308f
commit 52fb410deb
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 33 additions and 25 deletions

View File

@ -476,7 +476,7 @@ def usb_encode_device_for_qdb(device):
""" encode actual device name (xenstore doesn't allow dot in key names, so translated it into underscore) """ """ encode actual device name (xenstore doesn't allow dot in key names, so translated it into underscore) """
return device.replace('.', '_') return device.replace('.', '_')
def usb_list_vm(vm): def usb_list_vm(qvmc, vm):
if not vm.is_running(): if not vm.is_running():
return {} return {}
@ -512,7 +512,12 @@ def usb_list_vm(vm):
"Invalid %s device 'connected-to' in VM '%s'" % ( "Invalid %s device 'connected-to' in VM '%s'" % (
dev_name, vm.name) dev_name, vm.name)
continue continue
connected_to = untrusted_connected_to connected_to = qvmc.get_vm_by_name(untrusted_connected_to)
if connected_to is None:
print >>sys.stderr, \
"Device {} appears to be connected to {}, " \
"but such VM doesn't exist".format(
dev_name, untrusted_connected_to)
else: else:
connected_to = None connected_to = None
@ -531,7 +536,7 @@ def usb_list_vm(vm):
return devices return devices
def usb_list(qvmc=None, vm=None): def usb_list(qvmc, vm=None):
""" """
Returns a dictionary of USB devices (for PVUSB backends running in all VM). Returns a dictionary of USB devices (for PVUSB backends running in all VM).
The dictionary is keyed by 'name' (see below), each element is a dictionary itself: The dictionary is keyed by 'name' (see below), each element is a dictionary itself:
@ -546,16 +551,14 @@ def usb_list(qvmc=None, vm=None):
else: else:
vm_list = [vm] vm_list = [vm]
else: else:
if qvmc is None:
raise QubesException("You must pass either qvm or vm argument")
vm_list = qvmc.values() vm_list = qvmc.values()
devices_list = {} devices_list = {}
for vm in vm_list: for vm in vm_list:
devices_list.update(usb_list_vm(vm)) devices_list.update(usb_list_vm(qvmc, vm))
return devices_list return devices_list
def usb_check_attached(device): def usb_check_attached(qvmc, device):
"""Reread device attachment status""" """Reread device attachment status"""
vm = device['vm'] vm = device['vm']
untrusted_connected_to = vm.qdb.read( untrusted_connected_to = vm.qdb.read(
@ -565,22 +568,27 @@ def usb_check_attached(device):
raise QubesException( raise QubesException(
"Invalid %s device 'connected-to' in VM '%s'" % ( "Invalid %s device 'connected-to' in VM '%s'" % (
device['device'], vm.name)) device['device'], vm.name))
connected_to = untrusted_connected_to connected_to = qvmc.get_vm_by_name(untrusted_connected_to)
if connected_to is None:
print >>sys.stderr, \
"Device {} appears to be connected to {}, " \
"but such VM doesn't exist".format(
device['device'], untrusted_connected_to)
else: else:
connected_to = None connected_to = None
return connected_to return connected_to
def usb_attach(vm, device, auto_detach=False, wait=True): def usb_attach(qvmc, vm, device, auto_detach=False, wait=True):
if not vm.is_running(): if not vm.is_running():
raise QubesException("VM {} not running".format(vm.name)) raise QubesException("VM {} not running".format(vm.name))
if not device['vm'].is_running(): if not device['vm'].is_running():
raise QubesException("VM {} not running".format(device['vm'].name)) raise QubesException("VM {} not running".format(device['vm'].name))
connected_to = usb_check_attached(device) connected_to = usb_check_attached(qvmc, device)
if connected_to: if connected_to:
if auto_detach: if auto_detach:
usb_detach(device) usb_detach(qvmc, device)
else: else:
raise QubesException("Device {} already connected, to {}".format( raise QubesException("Device {} already connected, to {}".format(
device['name'], connected_to device['name'], connected_to
@ -629,12 +637,13 @@ def usb_attach(vm, device, auto_detach=False, wait=True):
f.seek(0) f.seek(0)
f.write(''.join(policy)) f.write(''.join(policy))
def usb_detach(vm, device): def usb_detach(qvmc, vm, device):
connected_to = usb_check_attached(device) connected_to = usb_check_attached(qvmc, device)
# detect race conditions; there is still race here, but much smaller # detect race conditions; there is still race here, but much smaller
if vm.name != connected_to: if connected_to is None or connected_to.qid != vm.qid:
raise QubesException( raise QubesException(
"Device {} not connected to VM {}".format(device['name'], vm.name)) "Device {} not connected to VM {}".format(
device['name'], vm.name))
p = vm.run_service('qubes.USBDetach', passio_popen=True, user='root') p = vm.run_service('qubes.USBDetach', passio_popen=True, user='root')
(stdout, stderr) = p.communicate( (stdout, stderr) = p.communicate(

View File

@ -97,7 +97,7 @@ def main():
backend_vm = qvm_collection.get_vm_by_name(args[1].split(":")[0]) backend_vm = qvm_collection.get_vm_by_name(args[1].split(":")[0])
if backend_vm is None: if backend_vm is None:
parser.error("No such VM: {}".format(args[1].split(":")[0])) parser.error("No such VM: {}".format(args[1].split(":")[0]))
dev_list = usb_list(vm=backend_vm) dev_list = usb_list(qvm_collection, vm=backend_vm)
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]]
@ -108,7 +108,7 @@ def main():
# kwargs['frontend'] = options.frontend # kwargs['frontend'] = options.frontend
kwargs['auto_detach'] = options.auto_detach kwargs['auto_detach'] = options.auto_detach
try: try:
usb_attach(vm, dev, **kwargs) usb_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,7 +125,7 @@ def main():
# kwargs['frontend'] = options.frontend # kwargs['frontend'] = options.frontend
# usb_detach(vm, **kwargs) # usb_detach(vm, **kwargs)
#else: #else:
usb_detach_all(vm) usb_detach_all(qvm_collection, vm)
else: else:
# Maybe usbvm:device? # Maybe usbvm:device?
@ -137,25 +137,24 @@ def main():
backend_vm = qvm_collection.get_vm_by_name(args[0].split(":")[0]) backend_vm = qvm_collection.get_vm_by_name(args[0].split(":")[0])
if backend_vm is None: if backend_vm is None:
parser.error("No such VM: {}".format(args[0].split(":")[0])) parser.error("No such VM: {}".format(args[0].split(":")[0]))
dev_list = usb_list(vm=backend_vm) dev_list = usb_list(qvm_collection, vm=backend_vm)
if not args[0] in dev_list.keys(): if not args[0] in dev_list.keys():
parser.error("Invalid device name: %s" % args[0]) parser.error("Invalid device name: %s" % args[0])
dev = dev_list[args[0]] dev = dev_list[args[0]]
attached_to = usb_check_attached(dev) attached_to = usb_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)
vm = qvm_collection.get_vm_by_name(attached_to) usb_detach(qvm_collection, attached_to, dev)
usb_detach(vm, dev)
else: else:
if len(args) > 0: if len(args) > 0:
parser.error("Too many parameters") parser.error("Too many parameters")
# do_list # do_list
for dev in usb_list(qvmc=qvm_collection).values(): for dev in usb_list(qvm_collection).values():
attached_to = usb_check_attached(dev) attached_to = dev['connected-to']
attached_to_str = "" attached_to_str = ""
if attached_to: if attached_to:
attached_to_str = " (attached to %s)" % (attached_to) attached_to_str = " (attached to %s)" % (attached_to.name)
print "%s\t%s%s" % (dev['name'], dev['desc'], attached_to_str) print "%s\t%s%s" % (dev['name'], dev['desc'], attached_to_str)
exit (0) exit (0)