Skip to content

Commit 064c9bb

Browse files
committed
Show "List USB Devices" option if sys-usb exists
Also show individual menu items if user has more than one usbvm resolves: QubesOS/qubes-issues#10131 resolves: QubesOS/qubes-issues#10202
1 parent 1789756 commit 064c9bb

File tree

3 files changed

+61
-19
lines changed

3 files changed

+61
-19
lines changed

qui/devices/actionable_widgets.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -361,20 +361,20 @@ async def widget_action(self, *_args):
361361
)
362362

363363

364-
#### Start sys-usb
364+
#### Start sys-usb (or other custom USBVMs)
365365

366366

367-
class StartSysUsb(ActionableWidget, SimpleActionWidget):
368-
def __init__(self, sysusb: backend.VM, variant: str = "dark"):
367+
class StartUSBVM(ActionableWidget, SimpleActionWidget):
368+
def __init__(self, usbvm: backend.VM, variant: str = "dark"):
369369
super().__init__(
370-
icon_name=sysusb.icon_name,
371-
text="<b>List USB Devices " "(start sys-usb)</b>",
370+
icon_name=usbvm.icon_name,
371+
text="<b>List USB Devices " "(start {})</b>".format(usbvm.name),
372372
variant=variant,
373373
)
374-
self.sysusb = sysusb
374+
self.usbvm = usbvm
375375

376376
async def widget_action(self, *_args):
377-
self.sysusb.vm_object.start()
377+
self.usbvm.vm_object.start()
378378

379379

380380
#### Configuration-related actions

qui/devices/backend.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ def is_attachable(self) -> bool:
8787
"""
8888
return self.vm_class != "AdminVM" and self._vm.is_running()
8989

90+
@property
91+
def is_usbvm(self) -> bool:
92+
"""
93+
Does the VM have a PCI USB controller attached to it?
94+
We do not need to cache this since it is checked only at Qui Devices
95+
initialization as well a PCI assignment/un-assignment
96+
"""
97+
if self._vm.virt_mode != "hvm":
98+
return False
99+
for dev in self._vm.devices["pci"].get_assigned_devices():
100+
for interface in dev.device.interfaces:
101+
if interface.category == DeviceCategory.PCI_USB:
102+
return True
103+
return False
104+
90105
@property
91106
def vm_object(self):
92107
"""

qui/devices/device_widget.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ def __init__(self, app_name, qapp, dispatcher):
112112
self.vms: Set[backend.VM] = set()
113113
self.dispvm_templates: Set[backend.VM] = set()
114114
self.parent_ports_to_hide = []
115-
self.sysusb: backend.VM | None = None
115+
self.active_usbvms: Set[backend.VM] = set()
116+
self.dormant_usbvms: Set[backend.VM] = set()
116117
self.dev_update_queue: Set = set()
117118
self.vm_update_queue: Set = set()
118119

@@ -144,6 +145,10 @@ def __init__(self, app_name, qapp, dispatcher):
144145
"device-unassign:" + devclass, self.device_unassigned
145146
)
146147

148+
self.dispatcher.add_handler("device-assign:pci", self.pci_action)
149+
self.dispatcher.add_handler("device-unassign:pci", self.pci_action)
150+
self.dispatcher.add_handler("domain-delete", self.remove_domain_item)
151+
147152
self.dispatcher.add_handler("domain-shutdown", self.vm_shutdown)
148153
self.dispatcher.add_handler("domain-start-failed", self.vm_shutdown)
149154
self.dispatcher.add_handler("domain-start", self.vm_start)
@@ -242,9 +247,12 @@ def initialize_vm_data(self):
242247
self.vms.add(wrapped_vm)
243248
if wrapped_vm.is_dispvm_template:
244249
self.dispvm_templates.add(wrapped_vm)
245-
if vm.name == "sys-usb":
246-
self.sysusb = wrapped_vm
247-
self.sysusb.is_running = vm.is_running()
250+
# Keep track of USBVMs
251+
if wrapped_vm.is_usbvm:
252+
if vm.is_running():
253+
self.active_usbvms.add(wrapped_vm)
254+
else:
255+
self.dormant_usbvms.add(wrapped_vm)
248256
except qubesadmin.exc.QubesException:
249257
# we don't have access to VM state
250258
pass
@@ -360,6 +368,23 @@ def device_unassigned(self, vm, _event, device, **_kwargs):
360368
# assigned. Cheers!
361369
return
362370

371+
def pci_action(self, vm, _event, _device, **_kwargs):
372+
# We assume PCI controllers could be assigned only when qube is shutdown
373+
wrapped_vm = backend.VM(vm)
374+
if wrapped_vm.is_usbvm:
375+
if wrapped_vm not in self.dormant_usbvms:
376+
self.dormant_usbvms.add(wrapped_vm)
377+
elif wrapped_vm in self.dormant_usbvms:
378+
self.dormant_usbvms.discard(wrapped_vm)
379+
380+
def remove_domain_item(self, _submitter, _event, vm, **_kwargs):
381+
# In a perfect world, core should trigger `device-unassign:pci` event
382+
# for PCI devices attached to an HVM before actually removing it and
383+
# this method should not be necessary. But we are not certain :/
384+
wrapped_vm = backend.VM(vm)
385+
if wrapped_vm in self.dormant_usbvms:
386+
self.dormant_usbvms.discard(wrapped_vm)
387+
363388
def update_single_feature(self, _vm, _event, feature, value=None, oldvalue=None):
364389
if not value:
365390
new = set()
@@ -533,8 +558,9 @@ def vm_start(self, vm, _event, **_kwargs):
533558
internal, attachable = False, False
534559
if attachable and not internal:
535560
self.vms.add(wrapped_vm)
536-
if wrapped_vm == self.sysusb:
537-
self.sysusb.is_running = True
561+
if wrapped_vm in self.dormant_usbvms:
562+
self.dormant_usbvms.discard(wrapped_vm)
563+
self.active_usbvms.add(wrapped_vm)
538564

539565
for devclass in DEV_TYPES:
540566
try:
@@ -548,8 +574,9 @@ def vm_start(self, vm, _event, **_kwargs):
548574

549575
def vm_shutdown(self, vm, _event, **_kwargs):
550576
wrapped_vm = backend.VM(vm)
551-
if wrapped_vm == self.sysusb:
552-
self.sysusb.is_running = False
577+
if wrapped_vm in self.active_usbvms:
578+
self.active_usbvms.discard(wrapped_vm)
579+
self.dormant_usbvms.add(wrapped_vm)
553580

554581
self.vms.discard(wrapped_vm)
555582
self.dispvm_templates.discard(wrapped_vm)
@@ -633,13 +660,13 @@ def show_menu(self, _unused, _event):
633660

634661
menu_items.append(device_item)
635662

636-
if not self.sysusb.is_running:
637-
sysusb_item = actionable_widgets.generate_wrapper_widget(
663+
for wrapped_vm in self.dormant_usbvms:
664+
usbvm_item = actionable_widgets.generate_wrapper_widget(
638665
Gtk.MenuItem,
639666
"activate",
640-
actionable_widgets.StartSysUsb(self.sysusb, theme),
667+
actionable_widgets.StartUSBVM(wrapped_vm, theme),
641668
)
642-
menu_items.append(sysusb_item)
669+
menu_items.append(usbvm_item)
643670

644671
for item in menu_items:
645672
tray_menu.add(item)

0 commit comments

Comments
 (0)