Merge ~kissiel/checkbox-support:fix-bad-landing into checkbox-support:master

Proposed by Maciej Kisielewski
Status: Merged
Approved by: Maciej Kisielewski
Approved revision: 98204f4fcc6410220bfef3551b1667e7282233e6
Merged at revision: 42df1c3010d1719130e296c91f441a5477136927
Proposed branch: ~kissiel/checkbox-support:fix-bad-landing
Merge into: checkbox-support:master
Diff against target: 681 lines (+36/-591)
4 files modified
checkbox_support/parsers/sysfs_usb.py (+0/-6)
checkbox_support/scripts/lsusb.py (+36/-540)
dev/null (+0/-43)
setup.py (+0/-2)
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Approve
Review via email: mp+392209@code.launchpad.net

Description of the change

Yesterday I landed the lsusb branch w/o the squashed commits (and review markers) being on it. This MR fixes it.

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

2020 !

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/checkbox_support/parsers/sysfs_usb.py b/checkbox_support/parsers/sysfs_usb.py
2index 56fbacd..148ea86 100644
3--- a/checkbox_support/parsers/sysfs_usb.py
4+++ b/checkbox_support/parsers/sysfs_usb.py
5@@ -153,8 +153,6 @@ def read_entry(sysfs_path, field):
6 return fentry.readline().strip('\n')
7
8
9-# REVIEW : the next two classes share a lot of functionality, I kept them
10-# separate as there are just two and it helps with readibility
11 class UsbInterface(dict):
12 """
13 A proxy to sysfs entry for a USB Interface.
14@@ -167,8 +165,6 @@ class UsbInterface(dict):
15 while parent:
16 self._level += 1
17 parent = parent.parent
18- # REVIEW : If this is too 'hucky' then I could just go with explicit
19- # assigment of the fields. May be more readible that way.
20 hex_int_fields = [
21 'bInterfaceClass', 'bInterfaceSubClass', 'bInterfaceProtocol']
22 for field in hex_int_fields:
23@@ -183,8 +179,6 @@ class UsbInterface(dict):
24 self['bInterfaceClass'], self['bInterfaceSubClass'],
25 self['bInterfaceProtocol'])
26
27- # REVIEW: I was tempted to overload __str__, but I went with an explicit
28- # function.
29 def to_str(self):
30 """Generate a string representation of this Interface."""
31 template = (
32diff --git a/checkbox_support/scripts/lsusb.py b/checkbox_support/scripts/lsusb.py
33index c243835..a2d4677 100755
34--- a/checkbox_support/scripts/lsusb.py
35+++ b/checkbox_support/scripts/lsusb.py
36@@ -1,547 +1,43 @@
37-#!/usr/bin/env python3
38-# lsusb.py
39-# Displays your USB devices in reasonable form.
40-# (c) Kurt Garloff <garloff@suse.de>, 2/2009, GPL v2 or v3.
41+# This file is part of Checkbox.
42 #
43-# Copyright 2016 Canonical Ltd.
44-# Sylvain Pineau <sylvain.pineau@canonical.com>
45+# Copyright 2020 Canonical Ltd.
46+# Written by:
47+# Maciej Kisielewski <maciej.kisielewski@canonical.com>
48 #
49-# Usage: See usage()
50-
51-from functools import total_ordering
52-import getopt
53-import os
54-import re
55-import sys
56-
57-# Global options
58-showint = False
59-showhubint = False
60-noemptyhub = False
61-nohub = False
62-warnsort = False
63-shortmode = False
64-
65-prefix = "/sys/bus/usb/devices/"
66-usbids = "/usr/share/usb.ids"
67-
68-esc = chr(27)
69-norm = esc + "[0;0m"
70-bold = esc + "[0;1m"
71-red = esc + "[0;31m"
72-green = esc + "[0;32m"
73-amber = esc + "[0;33m"
74-
75-cols = ("", "", "", "", "")
76-
77-usbvendors = []
78-usbproducts = []
79-usbclasses = []
80-
81-devlst = (
82- 'host', # usb-storage
83- 'video4linux/video', # uvcvideo et al.
84- 'sound/card', # snd-usb-audio
85- 'net/', # cdc_ether, ...
86- 'input/input', # usbhid
87- 'usb:hiddev', # usb hid
88- 'bluetooth/hci', # btusb
89- 'ttyUSB', # btusb
90- 'tty/', # cdc_acm
91- 'usb:lp', # usblp
92- 'usb/', # hiddev, usblp
93- )
94-
95-
96-def readattr(path, name):
97- "Read attribute from sysfs and return as string"
98- f = open(prefix + path + "/" + name)
99- return f.readline().rstrip("\n")
100-
101-
102-def readlink(path, name):
103- "Read symlink and return basename"
104- return os.path.basename(os.readlink(prefix + path + "/" + name))
105-
106-
107-@total_ordering
108-class UsbClass:
109- "Container for USB Class/Subclass/Protocol"
110-
111- def __init__(self, cl, sc, pr, str=""):
112- self.pclass = cl
113- self.subclass = sc
114- self.proto = pr
115- self.desc = str
116-
117- def __repr__(self):
118- return self.desc
119-
120- def __lt__(self, oth):
121- if self.pclass != oth.pclass:
122- return self.pclass - oth.pclass
123- if self.subclass != oth.subclass:
124- return self.subclass - oth.subclass
125- return self.proto - oth.proto
126-
127- def __eq__(self, oth):
128- if self.pclass != oth.pclass:
129- return False
130- if self.subclass != oth.subclass:
131- return False
132- return self.proto == oth.proto
133-
134-
135-@total_ordering
136-class UsbVendor:
137- "Container for USB Vendors"
138-
139- def __init__(self, vid, vname=""):
140- self.vid = vid
141- self.vname = vname
142-
143- def __repr__(self):
144- return self.vname
145-
146- def __lt__(self, oth):
147- return self.vid - oth.vid
148-
149- def __eq__(self, oth):
150- return self.vid == oth.vid
151-
152-
153-@total_ordering
154-class UsbProduct:
155- "Container for USB VID:PID devices"
156-
157- def __init__(self, vid, pid, pname=""):
158- self.vid = vid
159- self.pid = pid
160- self.pname = pname
161-
162- def __repr__(self):
163- return self.pname
164-
165- def __lt__(self, oth):
166- if self.vid != oth.vid:
167- return self.vid - oth.vid
168- return self.pid - oth.pid
169-
170- def __eq__(self, oth):
171- if self.vid != oth.vid:
172- return False
173- return self.pid == oth.pid
174-
175-
176-def ishexdigit(str):
177- "return True if all digits are valid hex digits"
178- for dg in str:
179- if not dg.isdigit() and dg not in 'abcdef':
180- return False
181- return True
182-
183-
184-def parse_usb_ids():
185- "Parse /usr/share/usb.ids and fill usbvendors, usbproducts, usbclasses"
186- id = 0
187- sid = 0
188- mode = 0
189- strg = ""
190- cstrg = ""
191- with open(usbids, encoding="utf-8", errors='ignore') as f:
192- for ln in f:
193- if ln[0] == '#':
194- continue
195- ln = ln.rstrip('\n')
196- if len(ln) == 0:
197- continue
198- if ishexdigit(ln[0:4]):
199- mode = 0
200- id = int(ln[:4], 16)
201- usbvendors.append(UsbVendor(id, ln[6:]))
202- continue
203- if ln[0] == '\t' and ishexdigit(ln[1:3]):
204- sid = int(ln[1:5], 16)
205- # USB devices
206- if mode == 0:
207- usbproducts.append(UsbProduct(id, sid, ln[7:]))
208- continue
209- elif mode == 1:
210- nm = ln[5:]
211- if nm != "Unused":
212- strg = cstrg + ":" + nm
213- else:
214- strg = cstrg + ":"
215- usbclasses.append(UsbClass(id, sid, -1, strg))
216- continue
217- if ln[0] == 'C':
218- mode = 1
219- id = int(ln[2:4], 16)
220- cstrg = ln[6:]
221- usbclasses.append(UsbClass(id, -1, -1, cstrg))
222- continue
223- if (
224- mode == 1 and ln[0] == '\t' and ln[1] == '\t' and
225- ishexdigit(ln[2:4])
226- ):
227- prid = int(ln[2:4], 16)
228- usbclasses.append(UsbClass(id, sid, prid, strg + ":" + ln[6:]))
229- continue
230- mode = 2
231-
232-
233-def find_usb_prod(vid, pid):
234- "Return device name from USB Vendor:Product list"
235- strg = ""
236- dev = UsbVendor(vid, "")
237- try:
238- strg = [v for v in usbvendors if v == dev][0].__repr__()
239- except IndexError:
240- return ""
241- dev = UsbProduct(vid, pid, "")
242- try:
243- strg += " " + [p for p in usbproducts if p == dev][0].__repr__()
244- except IndexError:
245- return strg
246- return strg
247-
248-
249-def find_usb_class(cid, sid, pid):
250- "Return USB protocol from usbclasses list"
251- if cid == 0xff and sid == 0xff and pid == 0xff:
252- return "Vendor Specific"
253- dev = UsbClass(cid, sid, pid, "")
254- try:
255- return [c for c in usbclasses if c == dev][0].__repr__()
256- except IndexError:
257- pass
258- dev = UsbClass(cid, sid, -1, "")
259- try:
260- return [c for c in usbclasses if c == dev][0].__repr__()
261- except IndexError:
262- pass
263- dev = UsbClass(cid, -1, -1, "")
264- try:
265- return [c for c in usbclasses if c == dev][0].__repr__()
266- except IndexError:
267- return ""
268-
269-
270-def find_storage(hostno):
271- "Return SCSI block dev names for host"
272- res = ""
273- for ent in os.listdir("/sys/class/scsi_device/"):
274- (host, bus, tgt, lun) = ent.split(":")
275- if host == hostno:
276- try:
277- path = "/sys/class/scsi_device/%s/device/block" % ent
278- for ent2 in os.listdir(path):
279- res += ent2 + " "
280- except:
281- pass
282- return res
283-
284-
285-def find_dev(driver, usbname):
286- "Return pseudo devname that's driven by driver"
287- res = ""
288- for nm in devlst:
289- dir = prefix + usbname
290- prep = ""
291- idx = nm.find('/')
292- if idx != -1:
293- prep = nm[:idx+1]
294- dir += "/" + nm[:idx]
295- nm = nm[idx+1:]
296- ln = len(nm)
297- try:
298- for ent in os.listdir(dir):
299- if ent[:ln] == nm:
300- res += prep+ent+" "
301- if nm == "host":
302- res += "(" + find_storage(ent[ln:])[:-1] + ")"
303- except:
304- pass
305- return res
306-
307-
308-class UsbInterface:
309- "Container for USB interface info"
310-
311- def __init__(self, parent=None, level=1):
312- self.parent = parent
313- self.level = level
314- self.fname = ""
315- self.iclass = 0
316- self.isclass = 0
317- self.iproto = 0
318- self.noep = 0
319- self.driver = ""
320- self.devname = ""
321- self.protoname = ""
322-
323- def read(self, fname):
324- fullpath = ""
325- if self.parent:
326- fullpath += self.parent.fname + "/"
327- fullpath += fname
328- self.fname = fname
329- self.iclass = int(readattr(fullpath, "bInterfaceClass"), 16)
330- self.isclass = int(readattr(fullpath, "bInterfaceSubClass"), 16)
331- self.iproto = int(readattr(fullpath, "bInterfaceProtocol"), 16)
332- self.noep = int(readattr(fullpath, "bNumEndpoints"))
333- try:
334- self.driver = readlink(fname, "driver")
335- self.devname = find_dev(self.driver, fname)
336- except:
337- pass
338- self.protoname = find_usb_class(self.iclass, self.isclass, self.iproto)
339-
340- def __str__(self):
341- return "%-16s(IF) %02x:%02x:%02x %iEPs (%s) %s%s %s%s%s\n" % \
342- (" " * self.level+self.fname, self.iclass,
343- self.isclass, self.iproto, self.noep,
344- self.protoname,
345- cols[3], self.driver,
346- cols[4], self.devname, cols[0])
347-
348-
349-class UsbDevice:
350- "Container for USB device info"
351-
352- def __init__(self, parent=None, level=0):
353- self.parent = parent
354- self.level = level
355- self.display_name = ""
356- self.fname = ""
357- self.busnum = 0
358- self.devnum = 0
359- self.iclass = 0
360- self.isclass = 0
361- self.iproto = 0
362- self.vid = 0
363- self.pid = 0
364- self.name = ""
365- self.usbver = ""
366- self.speed = ""
367- self.maxpower = ""
368- self.noports = 0
369- self.nointerfaces = 0
370- self.driver = ""
371- self.devname = ""
372- self.interfaces = []
373- self.children = []
374-
375- def read(self, fname):
376- self.fname = fname
377- self.iclass = int(readattr(fname, "bDeviceClass"), 16)
378- self.isclass = int(readattr(fname, "bDeviceSubClass"), 16)
379- self.iproto = int(readattr(fname, "bDeviceProtocol"), 16)
380- self.vid = int(readattr(fname, "idVendor"), 16)
381- self.pid = int(readattr(fname, "idProduct"), 16)
382- self.busnum = int(readattr(fname, "busnum"))
383- self.devnum = int(readattr(fname, "devnum"))
384- self.usbver = readattr(fname, "version")
385- try:
386- self.name = readattr(fname, "manufacturer") + " " \
387- + readattr(fname, "product")
388- if self.name[:5] == "Linux":
389- rx = re.compile(r"Linux [^ ]* .hci[-_]hcd")
390- mch = rx.match(self.name)
391- if mch:
392- self.name = "Linux Foundation %.2f root hub" % float(
393- self.usbver)
394- except:
395- pass
396- if not self.name:
397- self.name = find_usb_prod(self.vid, self.pid)
398- # Some USB Card readers have a better name than Generic ...
399- if self.name[:7] == "Generic":
400- oldnm = self.name
401- self.name = find_usb_prod(self.vid, self.pid)
402- if not self.name:
403- self.name = oldnm
404- self.speed = readattr(fname, "speed")
405- self.maxpower = readattr(fname, "bMaxPower")
406- self.noports = int(readattr(fname, "maxchild"))
407- try:
408- self.nointerfaces = int(readattr(fname, "bNumInterfaces"))
409- except:
410- self.nointerfaces = 0
411- try:
412- self.driver = readlink(fname, "driver")
413- self.devname = find_dev(self.driver, fname)
414- except:
415- pass
416-
417- def readchildren(self):
418- if self.fname[0:3] == "usb":
419- fname = self.fname[3:]
420- else:
421- fname = self.fname
422- for dirent in os.listdir(prefix + self.fname):
423- if not dirent[0:1].isdigit():
424- continue
425- if os.access(prefix + dirent + "/bInterfaceClass", os.R_OK):
426- iface = UsbInterface(self, self.level+1)
427- iface.read(dirent)
428- self.interfaces.append(iface)
429- else:
430- usbdev = UsbDevice(self, self.level+1)
431- usbdev.read(dirent)
432- usbdev.readchildren()
433- self.children.append(usbdev)
434-
435- def __str__(self):
436- if self.iclass == 9:
437- col = cols[2]
438- if noemptyhub and len(self.children) == 0:
439- return ""
440- if nohub:
441- str = ""
442- else:
443- col = cols[1]
444- if not nohub or self.iclass != 9:
445- if shortmode:
446- str = "ID %04x:%04x %s" % (self.vid, self.pid, self.name)
447- else:
448- str = "Bus %03d Device %03d: ID %04x:%04x %s" % \
449- (self.busnum, self.devnum, self.vid, self.pid, self.name)
450- str += "\n"
451- if showint:
452- for iface in self.interfaces:
453- str += iface.__str__()
454- for child in self.children:
455- str += child.__str__()
456- return str
457-
458-
459-def deepcopy(lst):
460- "Returns a deep copy from the list lst"
461- copy = []
462- for item in lst:
463- copy.append(item)
464- return copy
465-
466-
467-def display_diff(lst1, lst2, fmtstr, args):
468- "Compare lists (same length!) and display differences"
469- for idx in range(0, len(lst1)):
470- if lst1[idx] != lst2[idx]:
471- print("Warning: " + fmtstr % args(lst2[idx]))
472-
473-
474-def fix_usbvend():
475- "Sort USB vendor list and (optionally) display diffs"
476- if warnsort:
477- oldusbvend = deepcopy(usbvendors)
478- usbvendors.sort()
479- if warnsort:
480- display_diff(usbvendors, oldusbvend, "Unsorted Vendor ID %04x",
481- lambda x: (x.vid,))
482-
483-
484-def fix_usbprod():
485- "Sort USB products list"
486- if warnsort:
487- oldusbprod = deepcopy(usbproducts)
488- usbproducts.sort()
489- if warnsort:
490- display_diff(usbproducts, oldusbprod,
491- "Unsorted Vendor:Product ID %04x:%04x",
492- lambda x: (x.vid, x.pid))
493-
494-
495-def fix_usbclass():
496- "Sort USB class list"
497- if warnsort:
498- oldusbcls = deepcopy(usbclasses)
499- usbclasses.sort()
500- if warnsort:
501- display_diff(usbclasses, oldusbcls,
502- "Unsorted USB class %02x:%02x:%02x",
503- lambda x: (x.pclass, x.subclass, x.proto))
504-
505-
506-def usage():
507- "Displays usage information"
508- print("Usage: lsusb.py [options]")
509- print("Options:")
510- print(" -h display this help")
511- print(" -i display interface information")
512- print(" -I display interface information, even for hubs")
513- print(" -u suppress empty hubs")
514- print(" -U suppress all hubs")
515- print(" -c use colors")
516- print(" -s short mode")
517- print(" -w display warning if usb.ids is not sorted correctly")
518- print(" -f FILE override filename for /usr/share/usb.ids")
519- return 2
520-
521-
522-def read_usb():
523- "Read toplevel USB entries and print"
524- for dirent in os.listdir(prefix):
525- if not dirent[0:3] == "usb":
526- continue
527- usbdev = UsbDevice(None, 0)
528- usbdev.read(dirent)
529- usbdev.readchildren()
530- print(usbdev.__str__(), end="")
531+# Checkbox is free software: you can redistribute it and/or modify
532+# it under the terms of the GNU General Public License version 3,
533+# as published by the Free Software Foundation.
534+#
535+# Checkbox is distributed in the hope that it will be useful,
536+# but WITHOUT ANY WARRANTY; without even the implied warranty of
537+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
538+# GNU General Public License for more details.
539+#
540+# You should have received a copy of the GNU General Public License
541+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
542
543+import argparse
544+from checkbox_support.parsers import sysfs_usb
545
546 def main():
547- "main entry point"
548- global showint, showhubint, noemptyhub, nohub, warnsort, cols, usbids, \
549- shortmode
550- try:
551- (optlist, args) = getopt.gnu_getopt(sys.argv[1:], "hiIuUwcsf:", ("help",))
552- except getopt.GetoptError as exc:
553- print("Error:", exc)
554- sys.exit(usage())
555- for opt in optlist:
556- if opt[0] == "-h" or opt[0] == "--help":
557- usage()
558- sys.exit(0)
559- if opt[0] == "-i":
560- showint = True
561- continue
562- if opt[0] == "-I":
563- showint = True
564- showhubint = True
565- continue
566- if opt[0] == "-u":
567- noemptyhub = True
568- continue
569- if opt[0] == "-U":
570- noemptyhub = True
571- nohub = True
572- continue
573- if opt[0] == "-c":
574- cols = (norm, bold, red, green, amber)
575- continue
576- if opt[0] == "-w":
577- warnsort = True
578- continue
579- if opt[0] == "-f":
580- usbids = opt[1]
581- continue
582- if opt[0] == "-s":
583- shortmode = True
584- continue
585- if len(args) > 0:
586- print("Error: excess args %s ..." % args[0])
587- sys.exit(usage())
588- try:
589- parse_usb_ids()
590- fix_usbvend()
591- fix_usbprod()
592- fix_usbclass()
593- except:
594- print(" WARNING: Failure to read usb.ids", file=sys.stderr)
595- print(sys.exc_info(), file=sys.stderr)
596- read_usb()
597+ parser = argparse.ArgumentParser()
598+ parser.add_argument(
599+ '-s', '--short', action='store_true',
600+ help="Print output in a short form")
601+ parser.add_argument(
602+ '-l', '--long', action='store_true',
603+ help="Use the new output format")
604+ parser.add_argument('-f', '--file', help="Path to the usb.ids file")
605+ args = parser.parse_args()
606+
607+ usb_ids = sysfs_usb.UsbIds(args.file)
608+ for dev in sysfs_usb.get_usb_devices(usb_ids):
609+ if args.short:
610+ print(dev.to_short_str())
611+ elif args.long:
612+ print(dev.to_str())
613+ else:
614+ print(dev.to_legacy_str())
615
616-# Entry point
617-if __name__ == "__main__":
618+if __name__ == '__main__':
619 main()
620diff --git a/checkbox_support/scripts/lsusb3.py b/checkbox_support/scripts/lsusb3.py
621deleted file mode 100644
622index a2d4677..0000000
623--- a/checkbox_support/scripts/lsusb3.py
624+++ /dev/null
625@@ -1,43 +0,0 @@
626-# This file is part of Checkbox.
627-#
628-# Copyright 2020 Canonical Ltd.
629-# Written by:
630-# Maciej Kisielewski <maciej.kisielewski@canonical.com>
631-#
632-# Checkbox is free software: you can redistribute it and/or modify
633-# it under the terms of the GNU General Public License version 3,
634-# as published by the Free Software Foundation.
635-#
636-# Checkbox is distributed in the hope that it will be useful,
637-# but WITHOUT ANY WARRANTY; without even the implied warranty of
638-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
639-# GNU General Public License for more details.
640-#
641-# You should have received a copy of the GNU General Public License
642-# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
643-
644-import argparse
645-from checkbox_support.parsers import sysfs_usb
646-
647-def main():
648- parser = argparse.ArgumentParser()
649- parser.add_argument(
650- '-s', '--short', action='store_true',
651- help="Print output in a short form")
652- parser.add_argument(
653- '-l', '--long', action='store_true',
654- help="Use the new output format")
655- parser.add_argument('-f', '--file', help="Path to the usb.ids file")
656- args = parser.parse_args()
657-
658- usb_ids = sysfs_usb.UsbIds(args.file)
659- for dev in sysfs_usb.get_usb_devices(usb_ids):
660- if args.short:
661- print(dev.to_short_str())
662- elif args.long:
663- print(dev.to_str())
664- else:
665- print(dev.to_legacy_str())
666-
667-if __name__ == '__main__':
668- main()
669diff --git a/setup.py b/setup.py
670index d5d4a59..75dbc11 100755
671--- a/setup.py
672+++ b/setup.py
673@@ -93,8 +93,6 @@ setup(
674 "checkbox_support.scripts.eddystone_scanner:main"),
675 ("checkbox-support-lsusb="
676 "checkbox_support.scripts.lsusb:main"),
677- ("checkbox-support-lsusb3="
678- "checkbox_support.scripts.lsusb3:main"),
679 ],
680 },
681 )

Subscribers

People subscribed via source and target branches