Skip to content

Commit b589bf6

Browse files
committed
q-dev: update device utils
1 parent 63ae996 commit b589bf6

File tree

1 file changed

+55
-10
lines changed

1 file changed

+55
-10
lines changed

qubesusbproxy/utils.py

+55-10
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@
1919
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
2020
# USA.
2121
import asyncio
22+
import subprocess
2223

2324
import qubes
2425

26+
from typing import Type
27+
28+
from qubes import device_protocol
29+
from qubes.device_protocol import VirtualDevice
30+
2531

2632
def device_list_change(
2733
ext: qubes.ext.Extension, current_devices,
28-
vm, path, device_class
34+
vm, path, device_class: Type[qubes.device_protocol.DeviceInfo]
2935
):
3036
devclass = device_class.__name__[:-len('Device')].lower()
3137

@@ -39,7 +45,7 @@ def device_list_change(
3945
for dev_id, front_vm in detached.items():
4046
dev = device_class(vm, dev_id)
4147
asyncio.ensure_future(front_vm.fire_event_async(
42-
f'device-detach:{devclass}', port=dev))
48+
f'device-detach:{devclass}', port=dev.port))
4349
for dev_id in removed:
4450
device = device_class(vm, dev_id)
4551
vm.fire_event(f'device-removed:{devclass}', device=device)
@@ -54,17 +60,42 @@ def device_list_change(
5460

5561
ext.devices_cache[vm.name] = current_devices
5662

63+
to_attach = {}
5764
for front_vm in vm.app.domains:
5865
if not front_vm.is_running():
5966
continue
60-
for assignment in front_vm.devices[devclass].assignments(
61-
persistent=True):
62-
if (assignment.backend_domain == vm
63-
and assignment.port_id in added
64-
and assignment.port_id not in attached
65-
):
66-
asyncio.ensure_future(ext.attach_and_notify(
67-
front_vm, assignment.device, assignment.options))
67+
for assignment in front_vm.devices[devclass].get_assigned_devices():
68+
for device in assignment.devices:
69+
if (assignment.matches(device)
70+
and device.port_id in added
71+
and device.port_id not in attached
72+
):
73+
frontends = to_attach.get(device.port_id, {})
74+
# make it unique
75+
frontends[front_vm] = assignment.clone(
76+
device=VirtualDevice(device.port, device.device_id))
77+
to_attach[device.port_id] = frontends
78+
79+
for port_id, frontends in to_attach.items():
80+
if len(frontends) > 1:
81+
# unique
82+
device = tuple(frontends.values())[0].devices[0]
83+
target_name = confirm_device_attachment(device, frontends)
84+
for front in frontends:
85+
if front.name == target_name:
86+
target = front
87+
assignment = frontends[front]
88+
# already asked
89+
if assignment.mode.value == "ask-to-attach":
90+
assignment.mode = device_protocol.AssignmentMode.AUTO
91+
break
92+
else:
93+
return
94+
else:
95+
target = tuple(frontends.keys())[0]
96+
assignment = frontends[target]
97+
98+
asyncio.ensure_future(ext.attach_and_notify(target, assignment))
6899

69100

70101
def compare_device_cache(vm, devices_cache, current_devices):
@@ -101,3 +132,17 @@ def compare_device_cache(vm, devices_cache, current_devices):
101132
if cached_front is not None:
102133
detached[dev_id] = cached_front
103134
return added, attached, detached, removed
135+
136+
137+
def confirm_device_attachment(device, frontends) -> str:
138+
guivm = 'dom0' # TODO
139+
# TODO: guivm rpc?
140+
141+
proc = subprocess.Popen(
142+
["attach-confirm", guivm,
143+
device.backend_domain.name, device.port_id,
144+
device.description,
145+
*[f.name for f in frontends.keys()]],
146+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
147+
(target_name, _) = proc.communicate()
148+
return target_name.decode()

0 commit comments

Comments
 (0)