@@ -69,42 +69,51 @@ class Line:
69
69
"""Helper class to hold single device info for listing"""
70
70
71
71
# pylint: disable=too-few-public-methods
72
- def __init__ (self , device : DeviceInfo , attached_to = None ):
72
+ def __init__ (self , device : DeviceInfo , assignment = False ):
73
73
self .ident = "{!s}:{!s}" .format (
74
74
device .backend_domain , device .port_id )
75
75
self .description = device .description
76
- self .attached_to = attached_to if attached_to else ""
76
+ self .assignment = assignment
77
77
self .frontends = []
78
78
79
79
@property
80
80
def assignments (self ):
81
81
"""list of frontends the device is assigned to"""
82
- return ', ' .join (self .frontends )
82
+ fronts = (f'{ "*" if self .assignment else "" } ' + front
83
+ for front in self .frontends )
84
+ return ', ' .join (fronts )
83
85
84
86
85
87
def list_devices (args ):
86
88
"""
87
89
Called by the parser to execute the qubes-devices list subcommand. """
88
- app = args .app
89
-
90
90
domains = args .domains if hasattr (args , 'domains' ) else None
91
- devices = _load_devices (app , domains , args .devclass )
92
-
93
- result = {dev : Line (dev ) for dev in devices }
94
-
91
+ lines = _load_lines (args .app , domains , args .devclass , actual_devices = True )
92
+ lines = list (lines .values ())
93
+ if args .assignments :
94
+ extra_lines = _load_lines (
95
+ args .app , domains , args .devclass , actual_devices = False )
96
+ lines += list (extra_lines .values ())
97
+ qubesadmin .tools .print_table (prepare_table (lines ))
98
+
99
+
100
+ def _load_lines (app , domains , devclass , actual_devices : bool ):
101
+ devices = _load_devices (app , domains , devclass , actual_devices )
102
+ result = {dev : Line (dev , not actual_devices ) for dev in devices }
95
103
for dev in result :
96
104
for vm in app .domains :
97
- frontends = _load_frontends_info (vm , dev , args . devclass )
105
+ frontends = _load_frontends_info (vm , dev , devclass , actual_devices )
98
106
result [dev ].frontends .extend (frontends )
107
+ return result
99
108
100
- qubesadmin .tools .print_table (prepare_table (result .values ()))
101
109
102
-
103
- def _load_devices (app , domains , devclass ):
110
+ def _load_devices (app , domains , devclass , actual_devices ):
104
111
"""
105
112
Loads device exposed or connected to given domains.
106
113
107
114
If `domains` is empty/`None` load all devices.
115
+ If `actual_devices` is True only devices currently present will be included,
116
+ otherwise only device assignments
108
117
"""
109
118
devices = set ()
110
119
if domains :
@@ -115,12 +124,14 @@ def _load_devices(app, domains, devclass):
115
124
try :
116
125
for vm in domains :
117
126
try :
118
- for ass in vm .devices [devclass ].get_attached_devices ():
119
- devices .add (ass .device )
120
- for ass in vm .devices [devclass ].get_assigned_devices ():
121
- devices .add (ass .virtual_device )
122
- for dev in vm .devices [devclass ].get_exposed_devices ():
123
- devices .add (dev )
127
+ if actual_devices :
128
+ for ass in vm .devices [devclass ].get_attached_devices ():
129
+ devices .add (ass .device )
130
+ for dev in vm .devices [devclass ].get_exposed_devices ():
131
+ devices .add (dev )
132
+ else :
133
+ for ass in vm .devices [devclass ].get_assigned_devices ():
134
+ devices .add (ass .virtual_device )
124
135
except qubesadmin .exc .QubesVMNotFoundError :
125
136
if ignore_errors :
126
137
continue
@@ -132,20 +143,22 @@ def _load_devices(app, domains, devclass):
132
143
return devices
133
144
134
145
135
- def _load_frontends_info (vm , dev , devclass ):
146
+ def _load_frontends_info (vm , dev , devclass , actual_devices ):
136
147
"""
137
148
Returns string of vms to which a device is connected or `None`.
138
149
"""
139
150
if vm == dev .backend_domain :
140
151
return
141
152
142
153
try :
143
- for assignment in vm .devices [devclass ].get_attached_devices ():
144
- if dev in assignment .devices :
145
- yield _frontend_desc (vm , assignment )
146
- for assignment in vm .devices [devclass ].get_assigned_devices ():
147
- if dev == assignment .virtual_device :
148
- yield _frontend_desc (vm , assignment )
154
+ if actual_devices :
155
+ for assignment in vm .devices [devclass ].get_attached_devices ():
156
+ if dev in assignment .devices :
157
+ yield _frontend_desc (vm , assignment )
158
+ else :
159
+ for assignment in vm .devices [devclass ].get_assigned_devices ():
160
+ if dev == assignment .virtual_device :
161
+ yield _frontend_desc (vm , assignment )
149
162
except qubesadmin .exc .QubesVMNotFoundError :
150
163
pass
151
164
@@ -402,6 +415,12 @@ def init_list_parser(sub_parsers):
402
415
list_parser = sub_parsers .add_parser ('list' , aliases = ('ls' , 'l' ),
403
416
help = 'list devices' )
404
417
418
+ list_parser .add_argument ('--assignments' , '-s' ,
419
+ action = 'store_true' ,
420
+ default = False ,
421
+ help = "Include info about device assignments, "
422
+ "indicated by '*' before qube name." )
423
+
405
424
vm_name_group = qubesadmin .tools .VmNameGroup (
406
425
list_parser , required = False , vm_action = qubesadmin .tools .VmNameAction ,
407
426
help = 'list devices assigned to specific domain(s)' )
0 commit comments