Skip to content

Commit

Permalink
q-dev: fire device-attach on domain start
Browse files Browse the repository at this point in the history
fix device-list-change events
  • Loading branch information
piotrbartman committed Jun 1, 2024
1 parent b8513dc commit 1f3aa0c
Showing 1 changed file with 54 additions and 35 deletions.
89 changes: 54 additions & 35 deletions qubesusbproxy/core3ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,47 +421,66 @@ def on_qdb_change(self, vm, event, path):
current_devices = dict((dev.ident, dev.frontend_domain)
for dev in self.on_device_list_usb(vm, None))

# send events about devices detached/attached outside by themselves
# (like device pulled out or manual qubes.USB qrexec call)
# compare cached devices and current devices, collect:
# - newly appeared devices
# - devices disconnected from a vm
# - devices connected to a vm
new_devices = set()
connected_devices = dict()
disconnected_devices = dict()
devices_cache_for_vm = self.devices_cache[vm.name]
for dev_id, connected_to in current_devices.items():
if dev_id not in devices_cache_for_vm:
new_devices.add(dev_id)
device = USBDevice(vm, dev_id)
vm.fire_event('device-added:usb', device=device)
elif devices_cache_for_vm[dev_id] != current_devices[dev_id]:
if devices_cache_for_vm[dev_id] is not None:
disconnected_devices[dev_id] = devices_cache_for_vm[dev_id]
if current_devices[dev_id] is not None:
connected_devices[dev_id] = current_devices[dev_id]
for dev_id, connected_to in devices_cache_for_vm.items():
# - newly appeared devices (ident)
# - devices attached from a vm to frontend vm (ident: frontend_vm)
# - devices detached from frontend vm (ident: frontend_vm)
# - disappeared devices, e.g. plugged out (ident)
added = set()
attached = dict()
detached = dict()
removed = set()
cache = self.devices_cache[vm.name]
for dev_id, front_vm in current_devices.items():
if dev_id not in cache:
added.add(dev_id)
if front_vm is not None:
attached[dev_id] = front_vm
elif cache[dev_id] != front_vm:
cached_front = cache[dev_id]
if front_vm is None:
detached[dev_id] = cached_front
elif cached_front is None:
attached[dev_id] = front_vm
else:
# front changed from one to another, so we signal it as:
# detach from first one and attach to the second one.
detached[dev_id] = cached_front
attached[dev_id] = front_vm

for dev_id, cached_front in cache.items():
if dev_id not in current_devices:
device = USBDevice(vm, dev_id)
vm.fire_event('device-removed:usb', device=device)
removed.add(dev_id)
if cached_front is not None:
detached[dev_id] = cached_front

for dev_id, front_vm in detached.items():
dev = USBDevice(vm, dev_id)
asyncio.ensure_future(front_vm.fire_event_async(
'device-detach:usb', device=dev))
for dev_id in removed:
device = USBDevice(vm, dev_id)
vm.fire_event('device-removed:usb', device=device)
for dev_id in added:
device = USBDevice(vm, dev_id)
vm.fire_event('device-added:usb', device=device)
for dev_ident, front_vm in attached.items():
dev = USBDevice(vm, dev_ident)
asyncio.ensure_future(front_vm.fire_event_async(
'device-attach:usb', device=dev, options={}))

self.devices_cache[vm.name] = current_devices
# send events about devices detached/attached outside by themselves
# (like device pulled out or manual qubes.USB qrexec call)
for dev_ident, front_vm in disconnected_devices.items():
dev_id = USBDevice(vm, dev_ident)
asyncio.ensure_future(front_vm.fire_event_async('device-detach:usb',
device=dev_id))
for dev_ident, front_vm in connected_devices.items():
dev_id = USBDevice(vm, dev_ident)
asyncio.ensure_future(front_vm.fire_event_async('device-attach:usb',
device=dev_id,
options={}))

for front_vm in vm.app.domains:
if not front_vm.is_running():
continue
for assignment in front_vm.devices['usb'].get_assigned_devices():
if assignment.backend_domain == vm and \
assignment.ident in new_devices:
if (assignment.backend_domain == vm
and assignment.ident in added
and assignment.ident not in attached
):
asyncio.ensure_future(self._attach_and_notify(
front_vm, assignment.device, assignment.options))

Expand Down Expand Up @@ -610,8 +629,8 @@ async def on_device_detach_usb(self, vm, event, device):
async def on_domain_start(self, vm, _event, **_kwargs):
# pylint: disable=unused-argument
for assignment in vm.devices['usb'].get_assigned_devices():
device = assignment.device
await self.on_device_attach_usb(vm, '', device, options={})
asyncio.ensure_future(self._attach_and_notify(
vm, assignment.device, assignment.options))

@qubes.ext.handler('domain-shutdown')
async def on_domain_shutdown(self, vm, _event, **_kwargs):
Expand Down

0 comments on commit 1f3aa0c

Please sign in to comment.