8687.15.18
by Karl Fogel
Add the copyright header block to files under lib/canonical/. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
3 |
|
5265.2.2
by Abel Deuring
implemented revier's comments |
4 |
"""Parse Hardware Database submissions.
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
5 |
|
5265.2.2
by Abel Deuring
implemented revier's comments |
6 |
Base classes, intended to be used both for the commercial certification
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
7 |
data and for the community test submissions.
|
8 |
"""
|
|
9 |
||
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
10 |
__metaclass__ = type |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
11 |
__all__ = [ |
12 |
'SubmissionParser', |
|
13 |
'process_pending_submissions', |
|
14 |
]
|
|
15 |
||
16 |
import bz2 |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
17 |
from cStringIO import StringIO |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
18 |
|
12751.2.1
by j.c.sackett
Reformatted imports. |
19 |
#XXX: Given the version of python we know we're running on now,
|
20 |
# is the try/except here necessary?
|
|
9328.2.1
by Max Bowsher
Modify all imports of cElementTree to try both the Python 2.5+ and Python 2.4 names for the module. |
21 |
try: |
22 |
import xml.etree.cElementTree as etree |
|
23 |
except ImportError: |
|
24 |
import cElementTree as etree |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
25 |
from datetime import datetime, timedelta |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
26 |
from logging import getLogger |
5628.8.2
by Abel Deuring
implemented reviewer's comments |
27 |
import os |
28 |
import re |
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
29 |
import sys |
5915.2.1
by Abel Deuring
replace the lxml module by elementtree and by xmllint for RelaxNG valdidation |
30 |
|
5628.8.2
by Abel Deuring
implemented reviewer's comments |
31 |
import pytz |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
32 |
|
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
33 |
from zope.component import getUtility |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
34 |
from zope.interface import implements |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
35 |
|
6374.15.13
by Barry Warsaw
mergeRF |
36 |
from canonical.lazr.xml import RelaxNGValidator |
37 |
||
11382.6.33
by Gavin Panella
Convert all remaining uses of canonical.cachedproperty to lp.services.propertycache. |
38 |
from lp.services.propertycache import cachedproperty |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
39 |
from canonical.config import config |
7881.6.4
by Abel Deuring
re-implementation of handling Librarian errors in scripts/hwdbsubmissions.py, based on better error handling in FileDownloadClient.getFileByAlias(). |
40 |
from canonical.librarian.interfaces import LibrarianServerError |
10234.3.3
by Curtis Hovey
Migrated hardward database to lp. Updated test_doc to run the hwddb test. |
41 |
from lp.hardwaredb.interfaces.hwdb import ( |
12751.2.1
by j.c.sackett
Reformatted imports. |
42 |
HWBus, |
43 |
HWSubmissionProcessingStatus, |
|
44 |
IHWDeviceDriverLinkSet, |
|
45 |
IHWDeviceSet, |
|
46 |
IHWDriverSet, |
|
47 |
IHWSubmissionDeviceSet, |
|
48 |
IHWSubmissionSet, |
|
49 |
IHWVendorIDSet, |
|
50 |
IHWVendorNameSet, |
|
51 |
)
|
|
7508.1.1
by Abel Deuring
fix for bug 314342: HWDB submission processing script does not process private submissions |
52 |
from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
53 |
from canonical.launchpad.interfaces.looptuner import ITunableLoop |
54 |
from canonical.launchpad.utilities.looptuner import LoopTuner |
|
55 |
from canonical.launchpad.webapp.errorlog import ( |
|
12751.2.1
by j.c.sackett
Reformatted imports. |
56 |
ErrorReportingUtility, |
57 |
ScriptRequest, |
|
58 |
)
|
|
12751.2.4
by j.c.sackett
Added a context manager to allow the disabling of oops handling when needed in cronscripts, and updated tests. |
59 |
from lp.services.scripts.base import disable_oops_handler |
5265.2.2
by Abel Deuring
implemented revier's comments |
60 |
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
61 |
_relax_ng_files = { |
5265.2.2
by Abel Deuring
implemented revier's comments |
62 |
'1.0': 'hardware-1_0.rng', } |
63 |
||
5628.8.2
by Abel Deuring
implemented reviewer's comments |
64 |
_time_regex = re.compile(r""" |
65 |
^(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)
|
|
66 |
T(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)
|
|
67 |
(?:\.(?P<second_fraction>\d{0,6}))?
|
|
68 |
(?P<tz>
|
|
69 |
(?:(?P<tz_sign>[-+])(?P<tz_hour>\d\d):(?P<tz_minute>\d\d))
|
|
70 |
| Z)?$
|
|
71 |
""", |
|
72 |
re.VERBOSE) |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
73 |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
74 |
ROOT_UDI = '/org/freedesktop/Hal/devices/computer' |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
75 |
UDEV_ROOT_PATH = '/devices/LNXSYSTM:00' |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
76 |
|
8294.5.1
by Abel Deuring
Fix for bug 336613: ignore certain duplicate UDIs in HWDB submissions |
77 |
# These UDIs appears in some submissions more than once.
|
78 |
KNOWN_DUPLICATE_UDIS = set(( |
|
79 |
'/org/freedesktop/Hal/devices/ssb__null_', |
|
80 |
'/org/freedesktop/Hal/devices/uinput', |
|
81 |
'/org/freedesktop/Hal/devices/ignored-device', |
|
82 |
))
|
|
83 |
||
6261.2.5
by Abel Deuring
implemented reviewer's commets |
84 |
# See include/linux/pci_ids.h in the Linux kernel sources for a complete
|
85 |
# list of PCI class and subclass codes.
|
|
6261.2.6
by Abel Deuring
implemented reviewer's comments |
86 |
PCI_CLASS_STORAGE = 1 |
87 |
PCI_SUBCLASS_STORAGE_SATA = 6 |
|
88 |
||
89 |
PCI_CLASS_BRIDGE = 6 |
|
90 |
PCI_SUBCLASS_BRIDGE_PCI = 4 |
|
91 |
PCI_SUBCLASS_BRIDGE_CARDBUS = 7 |
|
92 |
||
6261.2.5
by Abel Deuring
implemented reviewer's commets |
93 |
PCI_CLASS_SERIALBUS_CONTROLLER = 12 |
6261.2.6
by Abel Deuring
implemented reviewer's comments |
94 |
PCI_SUBCLASS_SERIALBUS_USB = 3 |
5915.2.1
by Abel Deuring
replace the lxml module by elementtree and by xmllint for RelaxNG valdidation |
95 |
|
6533.1.2
by Abel Deuring
implemented reviewer's comments |
96 |
WARNING_NO_HAL_KERNEL_VERSION = 1 |
97 |
WARNING_NO_KERNEL_PACKAGE_DATA = 2 |
|
98 |
||
99 |
DB_FORMAT_FOR_VENDOR_ID = { |
|
100 |
'pci': '0x%04x', |
|
101 |
'usb_device': '0x%04x', |
|
102 |
'scsi': '%-8s', |
|
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
103 |
'scsi_device': '%-8s', |
6533.1.2
by Abel Deuring
implemented reviewer's comments |
104 |
}
|
105 |
||
106 |
DB_FORMAT_FOR_PRODUCT_ID = { |
|
107 |
'pci': '0x%04x', |
|
108 |
'usb_device': '0x%04x', |
|
109 |
'scsi': '%-16s', |
|
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
110 |
'scsi_device': '%-16s', |
6533.1.2
by Abel Deuring
implemented reviewer's comments |
111 |
}
|
112 |
||
9644.3.8
by Abel Deuring
implemented reviewer's comments |
113 |
UDEV_USB_DEVICE_PROPERTIES = set(('DEVTYPE', 'PRODUCT', 'TYPE')) |
114 |
UDEV_USB_PRODUCT_RE = re.compile( |
|
115 |
'^[0-9a-f]{1,4}/[0-9a-f]{1,4}/[0-9a-f]{1,4}$', re.I) |
|
116 |
UDEV_USB_TYPE_RE = re.compile('^[0-9]{1,3}/[0-9]{1,3}/[0-9]{1,3}$') |
|
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
117 |
SYSFS_SCSI_DEVICE_ATTRIBUTES = set(('vendor', 'model', 'type')) |
9644.3.8
by Abel Deuring
implemented reviewer's comments |
118 |
|
7184.4.4
by Abel Deuring
moved the definition of test classes derived from SubmissionParser from test methods to to top-level |
119 |
class SubmissionParser(object): |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
120 |
"""A Parser for the submissions to the hardware database."""
|
121 |
||
122 |
def __init__(self, logger=None): |
|
123 |
if logger is None: |
|
124 |
logger = getLogger() |
|
125 |
self.logger = logger |
|
5915.2.1
by Abel Deuring
replace the lxml module by elementtree and by xmllint for RelaxNG valdidation |
126 |
self.doc_parser = etree.XMLParser() |
6533.1.2
by Abel Deuring
implemented reviewer's comments |
127 |
self._logged_warnings = set() |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
128 |
|
129 |
self.validator = {} |
|
5265.2.2
by Abel Deuring
implemented revier's comments |
130 |
directory = os.path.join(config.root, 'lib', 'canonical', |
131 |
'launchpad', 'scripts') |
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
132 |
for version, relax_ng_filename in _relax_ng_files.items(): |
5265.2.2
by Abel Deuring
implemented revier's comments |
133 |
path = os.path.join(directory, relax_ng_filename) |
5915.2.1
by Abel Deuring
replace the lxml module by elementtree and by xmllint for RelaxNG valdidation |
134 |
self.validator[version] = RelaxNGValidator(path) |
5628.8.3
by Abel Deuring
implemented reviewer's comments |
135 |
self._setMainSectionParsers() |
136 |
self._setHardwareSectionParsers() |
|
137 |
self._setSoftwareSectionParsers() |
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
138 |
|
12751.2.4
by j.c.sackett
Added a context manager to allow the disabling of oops handling when needed in cronscripts, and updated tests. |
139 |
def _logError(self, message, submission_key, create_oops=True): |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
140 |
"""Log `message` for an error in submission submission_key`."""
|
12751.2.4
by j.c.sackett
Added a context manager to allow the disabling of oops handling when needed in cronscripts, and updated tests. |
141 |
msg = 'Parsing submission %s: %s' % (submission_key, message) |
142 |
if not create_oops: |
|
143 |
with disable_oops_handler(self.logger): |
|
144 |
self.logger.error(msg) |
|
145 |
else: |
|
146 |
self.logger.error(msg) |
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
147 |
|
6533.1.3
by Abel Deuring
implemented more reviewer comments. |
148 |
def _logWarning(self, message, warning_id=None): |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
149 |
"""Log `message` for a warning in submission submission_key`."""
|
6533.1.3
by Abel Deuring
implemented more reviewer comments. |
150 |
if warning_id is None: |
151 |
issue_warning = True |
|
152 |
elif warning_id not in self._logged_warnings: |
|
153 |
issue_warning = True |
|
154 |
self._logged_warnings.add(warning_id) |
|
155 |
else: |
|
156 |
issue_warning = False |
|
157 |
if issue_warning: |
|
158 |
self.logger.warning( |
|
159 |
'Parsing submission %s: %s' % (self.submission_key, message)) |
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
160 |
|
5265.2.2
by Abel Deuring
implemented revier's comments |
161 |
def _getValidatedEtree(self, submission, submission_key): |
162 |
"""Create an etree doc from the XML string submission and validate it.
|
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
163 |
|
5265.2.2
by Abel Deuring
implemented revier's comments |
164 |
:return: an `lxml.etree` instance representation of a valid
|
165 |
submission or None for invalid submissions.
|
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
166 |
"""
|
167 |
try: |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
168 |
tree = etree.parse(StringIO(submission), parser=self.doc_parser) |
5915.2.1
by Abel Deuring
replace the lxml module by elementtree and by xmllint for RelaxNG valdidation |
169 |
except SyntaxError, error_value: |
5265.2.2
by Abel Deuring
implemented revier's comments |
170 |
self._logError(error_value, submission_key) |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
171 |
return None |
172 |
||
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
173 |
submission_doc = tree.getroot() |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
174 |
if submission_doc.tag != 'system': |
5265.2.2
by Abel Deuring
implemented revier's comments |
175 |
self._logError("root node is not '<system>'", submission_key) |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
176 |
return None |
177 |
version = submission_doc.attrib.get('version', None) |
|
178 |
if not version in self.validator.keys(): |
|
5265.2.2
by Abel Deuring
implemented revier's comments |
179 |
self._logError( |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
180 |
'invalid submission format version: %s' % repr(version), |
181 |
submission_key) |
|
182 |
return None |
|
183 |
self.submission_format_version = version |
|
184 |
||
185 |
validator = self.validator[version] |
|
5915.2.1
by Abel Deuring
replace the lxml module by elementtree and by xmllint for RelaxNG valdidation |
186 |
if not validator.validate(submission): |
5265.2.2
by Abel Deuring
implemented revier's comments |
187 |
self._logError( |
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
188 |
'Relax NG validation failed.\n%s' % validator.error_log, |
12751.2.4
by j.c.sackett
Added a context manager to allow the disabling of oops handling when needed in cronscripts, and updated tests. |
189 |
submission_key, |
190 |
create_oops=False) |
|
5265.2.1
by Abel Deuring
Validaton of HWDB submissins, step 1 |
191 |
return None |
192 |
return submission_doc |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
193 |
|
194 |
def _getValueAttributeAsBoolean(self, node): |
|
195 |
"""Return the value of the attribute "value" as a boolean."""
|
|
196 |
value = node.attrib['value'] |
|
197 |
# Paranoia check: The Relax NG validation already ensures that the
|
|
198 |
# attribute value is either 'True' or 'False'.
|
|
199 |
assert value in ('True', 'False'), ( |
|
200 |
'Parsing submission %s: Boolean value for attribute "value" ' |
|
201 |
'expected in tag <%s>' % (self.submission_key, node.tag)) |
|
202 |
return value == 'True' |
|
203 |
||
204 |
def _getValueAttributeAsString(self, node): |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
205 |
"""Return the value of the attribute "value"."""
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
206 |
# The Relax NG validation ensures that the attribute exists.
|
207 |
return node.attrib['value'] |
|
208 |
||
209 |
def _getValueAttributeAsDateTime(self, time_node): |
|
5628.8.2
by Abel Deuring
implemented reviewer's comments |
210 |
"""Convert a "value" attribute into a datetime object."""
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
211 |
time_text = time_node.get('value') |
212 |
||
213 |
# we cannot use time.strptime: this function accepts neither fractions
|
|
214 |
# of a second nor a time zone given e.g. as '+02:30'.
|
|
215 |
mo = _time_regex.search(time_text) |
|
216 |
||
5628.8.2
by Abel Deuring
implemented reviewer's comments |
217 |
# The Relax NG schema allows a leading minus sign and year numbers
|
218 |
# with more than four digits, which are not "covered" by _time_regex.
|
|
219 |
if mo is None: |
|
220 |
raise ValueError( |
|
221 |
'Timestamp with unreasonable value: %s' % time_text) |
|
222 |
||
223 |
time_parts = mo.groupdict() |
|
224 |
||
225 |
year = int(time_parts['year']) |
|
226 |
month = int(time_parts['month']) |
|
227 |
day = int(time_parts['day']) |
|
228 |
hour = int(time_parts['hour']) |
|
229 |
minute = int(time_parts['minute']) |
|
230 |
second = int(time_parts['second']) |
|
231 |
second_fraction = time_parts['second_fraction'] |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
232 |
if second_fraction is not None: |
5628.8.2
by Abel Deuring
implemented reviewer's comments |
233 |
milliseconds = second_fraction + '0' * (6 - len(second_fraction)) |
234 |
milliseconds = int(milliseconds) |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
235 |
else: |
5628.8.2
by Abel Deuring
implemented reviewer's comments |
236 |
milliseconds = 0 |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
237 |
|
238 |
# The Relax NG validator accepts leap seconds, but the datetime
|
|
239 |
# constructor rejects them. The time values submitted by the HWDB
|
|
240 |
# client are not necessarily very precise, hence we can round down
|
|
241 |
# to 59.999999 seconds without losing any real precision.
|
|
242 |
if second > 59: |
|
243 |
second = 59 |
|
5628.8.2
by Abel Deuring
implemented reviewer's comments |
244 |
milliseconds = 999999 |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
245 |
|
246 |
timestamp = datetime(year, month, day, hour, minute, second, |
|
5628.8.2
by Abel Deuring
implemented reviewer's comments |
247 |
milliseconds, tzinfo=pytz.timezone('utc')) |
248 |
||
249 |
tz_sign = time_parts['tz_sign'] |
|
250 |
tz_hour = time_parts['tz_hour'] |
|
251 |
tz_minute = time_parts['tz_minute'] |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
252 |
if tz_sign in ('-', '+'): |
253 |
delta = timedelta(hours=int(tz_hour), minutes=int(tz_minute)) |
|
254 |
if tz_sign == '-': |
|
255 |
timestamp = timestamp + delta |
|
256 |
else: |
|
257 |
timestamp = timestamp - delta |
|
258 |
return timestamp |
|
259 |
||
260 |
def _getClientData(self, client_node): |
|
261 |
"""Parse the <client> node in the <summary> section.
|
|
262 |
||
263 |
:return: A dictionary with keys 'name', 'version', 'plugins'.
|
|
8037.2.1
by Brad Crittenden
fixed annoying typos |
264 |
Name and version describe the client program that
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
265 |
produced the submission. Pugins is a list with one
|
266 |
entry per client plugin; each entry is dictionary with
|
|
267 |
the keys 'name' and 'version'.
|
|
268 |
"""
|
|
269 |
result = {'name': client_node.get('name'), |
|
270 |
'version': client_node.get('version')} |
|
271 |
plugins = result['plugins'] = [] |
|
272 |
for node in client_node.getchildren(): |
|
273 |
# Ensured by the Relax NG validation: The only allowed sub-tag
|
|
274 |
# of <client> is <plugin>, which has the attributes 'name' and
|
|
275 |
# 'version'.
|
|
276 |
plugins.append({'name': node.get('name'), |
|
277 |
'version': node.get('version')}) |
|
278 |
return result |
|
279 |
||
280 |
_parse_summary_section = { |
|
281 |
'live_cd': _getValueAttributeAsBoolean, |
|
282 |
'system_id': _getValueAttributeAsString, |
|
283 |
'distribution': _getValueAttributeAsString, |
|
284 |
'distroseries': _getValueAttributeAsString, |
|
285 |
'architecture': _getValueAttributeAsString, |
|
286 |
'private': _getValueAttributeAsBoolean, |
|
287 |
'contactable': _getValueAttributeAsBoolean, |
|
288 |
'date_created': _getValueAttributeAsDateTime, |
|
289 |
'client': _getClientData, |
|
9580.6.4
by Abel Deuring
Added ykernel-release> to the dictionary of known sub-nodes of <summary> for HWDB submissions |
290 |
'kernel-release': _getValueAttributeAsString, |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
291 |
}
|
292 |
||
293 |
def _parseSummary(self, summary_node): |
|
294 |
"""Parse the <summary> part of a submission.
|
|
295 |
||
296 |
:return: A dictionary with the keys 'live_cd', 'system_id',
|
|
297 |
'distribution', 'distroseries', 'architecture',
|
|
298 |
'private', 'contactable', 'date_created', 'client'.
|
|
299 |
See the sample XML file tests/hardwaretest.xml for
|
|
300 |
detailed description of the values.
|
|
301 |
"""
|
|
302 |
summary = {} |
|
303 |
# The Relax NG validation ensures that we have exactly those
|
|
304 |
# sub-nodes that are listed in _parse_summary_section.
|
|
305 |
for node in summary_node.getchildren(): |
|
306 |
parser = self._parse_summary_section[node.tag] |
|
307 |
summary[node.tag] = parser(self, node) |
|
308 |
return summary |
|
309 |
||
310 |
def _getValueAndType(self, node): |
|
311 |
"""Return (value, type) of a <property> or <value> node."""
|
|
312 |
type_ = node.get('type') |
|
313 |
if type_ in ('dbus.Boolean', 'bool'): |
|
314 |
value = node.text.strip() |
|
315 |
# Pure paranoia: The Relax NG validation ensures that <property>
|
|
316 |
# and <value> tags have only the allowed values.
|
|
317 |
assert value in ('True', 'False'), ( |
|
318 |
'Parsing submission %s: Invalid bool value for <property> or ' |
|
319 |
'<value>: %s' % (self.submission_key, repr(value))) |
|
320 |
return (value == 'True', type_) |
|
321 |
elif type_ in ('str', 'dbus.String', 'dbus.UTF8String'): |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
322 |
return (node.text.strip(), type_) |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
323 |
elif type_ in ('dbus.Byte', 'dbus.Int16', 'dbus.Int32', 'dbus.Int64', |
324 |
'dbus.UInt16', 'dbus.UInt32', 'dbus.UInt64', 'int', |
|
325 |
'long'): |
|
326 |
value = node.text.strip() |
|
327 |
return (int(value), type_) |
|
328 |
elif type_ in ('dbus.Double', 'float'): |
|
329 |
value = node.text.strip() |
|
330 |
return (float(value), type_) |
|
331 |
elif type_ in ('dbus.Array', 'list'): |
|
332 |
value = [] |
|
333 |
for sub_node in node.getchildren(): |
|
334 |
value.append(self._getValueAndType(sub_node)) |
|
335 |
return (value, type_) |
|
336 |
elif type_ in ('dbus.Dictionary', 'dict'): |
|
337 |
value = {} |
|
338 |
for sub_node in node.getchildren(): |
|
339 |
value[sub_node.get('name')] = self._getValueAndType(sub_node) |
|
340 |
return (value, type_) |
|
341 |
else: |
|
342 |
# This should not happen: The Relax NG validation ensures
|
|
343 |
# that we have only those values for type_ that appear in
|
|
344 |
# the if/elif expressions above.
|
|
345 |
raise AssertionError( |
|
346 |
'Parsing submission %s: Unexpected <property> or <value> ' |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
347 |
'type: %s' % (self.submission_key, type_)) |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
348 |
|
349 |
def _parseProperty(self, property_node): |
|
350 |
"""Parse a <property> node.
|
|
351 |
||
352 |
:return: (name, (value, type)) of a property.
|
|
353 |
"""
|
|
354 |
property_name = property_node.get('name') |
|
355 |
return (property_node.get('name'), |
|
356 |
self._getValueAndType(property_node)) |
|
357 |
||
358 |
def _parseProperties(self, properties_node): |
|
359 |
"""Parse <property> sub-nodes of properties_node.
|
|
360 |
||
361 |
:return: A dictionary, where each key is the name of a property;
|
|
362 |
the values are the tuples (value, type) of a property.
|
|
363 |
"""
|
|
364 |
properties = {} |
|
365 |
for property_node in properties_node.getchildren(): |
|
366 |
# Paranoia check: The Relax NG schema ensures that a node
|
|
367 |
# with <property> sub-nodes has no other sub-nodes
|
|
368 |
assert property_node.tag == 'property', ( |
|
369 |
'Parsing submission %s: Found <%s> node, expected <property>' |
|
370 |
% (self.submission_key, property_node.tag)) |
|
371 |
property_name, property_value = self._parseProperty(property_node) |
|
372 |
if property_name in properties.keys(): |
|
373 |
raise ValueError( |
|
374 |
'<property name="%s"> found more than once in <%s>' |
|
375 |
% (property_name, properties_node.tag)) |
|
376 |
properties[property_name] = property_value |
|
377 |
return properties |
|
378 |
||
379 |
def _parseDevice(self, device_node): |
|
380 |
"""Parse a HAL <device> node.
|
|
381 |
||
382 |
:return: A dictionary d with the keys 'id', 'udi', 'parent',
|
|
383 |
'properties'. d['id'] is an ID of the device d['udi']
|
|
384 |
is the HAL UDI of the device; d['properties'] is a
|
|
385 |
dictionary with the properties of the device (see
|
|
386 |
_parseProperties for details).
|
|
387 |
"""
|
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
388 |
# The Relax NG validation ensures that the attributes "id" and
|
389 |
# "udi" exist; it also ensures that "id" contains an integer.
|
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
390 |
device_data = {'id': int(device_node.get('id')), |
5628.8.3
by Abel Deuring
implemented reviewer's comments |
391 |
'udi': device_node.get('udi')} |
392 |
parent = device_node.get('parent', None) |
|
393 |
if parent is not None: |
|
394 |
parent = int(parent.strip()) |
|
395 |
device_data['parent'] = parent |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
396 |
device_data['properties'] = self._parseProperties(device_node) |
397 |
return device_data |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
398 |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
399 |
def _parseHAL(self, hal_node): |
400 |
"""Parse the <hal> section of a submission.
|
|
401 |
||
402 |
:return: A list, where each entry is the result of a _parseDevice
|
|
403 |
call.
|
|
404 |
"""
|
|
405 |
# The Relax NG validation ensures that <hal> has the attribute
|
|
406 |
# "version"
|
|
407 |
hal_data = {'version': hal_node.get('version')} |
|
408 |
hal_data['devices'] = devices = [] |
|
409 |
for device_node in hal_node.getchildren(): |
|
410 |
# Pure paranoia: The Relax NG validation ensures already
|
|
411 |
# that we have only <device> tags within <hal>
|
|
412 |
assert device_node.tag == 'device', ( |
|
413 |
'Parsing submission %s: Unexpected tag <%s> in <hal>' |
|
414 |
% (self.submission_key, device_node.tag)) |
|
415 |
devices.append(self._parseDevice(device_node)) |
|
416 |
return hal_data |
|
417 |
||
418 |
def _parseProcessors(self, processors_node): |
|
419 |
"""Parse the <processors> node.
|
|
420 |
||
421 |
:return: A list of dictionaries, where each dictionary d contains
|
|
422 |
the data of a <processor> node. The dictionary keys are
|
|
423 |
'id', 'name', 'properties'. d['id'] is an ID of a
|
|
424 |
<processor> node, d['name'] its name, and d['properties']
|
|
425 |
contains the properties of a processor (see
|
|
426 |
_parseProperties for details).
|
|
427 |
"""
|
|
428 |
result = [] |
|
429 |
for processor_node in processors_node.getchildren(): |
|
430 |
# Pure paranoia: The Relax NG valiation ensures already
|
|
431 |
# the we have only <processor> as sub-tags of <processors>.
|
|
432 |
assert processor_node.tag == 'processor', ( |
|
433 |
'Parsing submission %s: Unexpected tag <%s> in <processors>' |
|
434 |
% (self.submission_key, processors_node.tag)) |
|
435 |
processor = {} |
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
436 |
# The RelaxNG validation ensures that the attribute "id" exists
|
437 |
# and that it contains an integer.
|
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
438 |
processor['id'] = int(processor_node.get('id')) |
439 |
processor['name'] = processor_node.get('name') |
|
440 |
processor['properties'] = self._parseProperties(processor_node) |
|
441 |
result.append(processor) |
|
442 |
return result |
|
443 |
||
444 |
def _parseAliases(self, aliases_node): |
|
445 |
"""Parse the <aliases> node.
|
|
446 |
||
447 |
:return: A list of dictionaries, where each dictionary d has the
|
|
448 |
keys 'id', 'vendor', 'model'. d['id'] is the ID of a
|
|
449 |
HAL device; d['vendor'] is an alternative vendor name of
|
|
450 |
the device; d['model'] is an alternative model name.
|
|
451 |
||
452 |
See tests/hardwaretest.xml more more details.
|
|
453 |
"""
|
|
454 |
aliases = [] |
|
455 |
for alias_node in aliases_node.getchildren(): |
|
456 |
# Pure paranoia: The Relax NG valiation ensures already
|
|
457 |
# the we have only <alias> tags within <aliases>
|
|
458 |
assert alias_node.tag == 'alias', ( |
|
459 |
'Parsing submission %s: Unexpected tag <%s> in <aliases>' |
|
460 |
% (self.submission_key, alias_node.tag)) |
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
461 |
# The RelaxNG validation ensures that the attribute "target"
|
462 |
# exists and that it contains an integer.
|
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
463 |
alias = {'target': int(alias_node.get('target'))} |
464 |
for sub_node in alias_node.getchildren(): |
|
465 |
# The Relax NG svalidation ensures that we have exactly
|
|
466 |
# two subnodes: <vendor> and <model>
|
|
467 |
alias[sub_node.tag] = sub_node.text.strip() |
|
468 |
aliases.append(alias) |
|
469 |
return aliases |
|
470 |
||
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
471 |
def _parseUdev(self, udev_node): |
472 |
"""Parse the <udev> node.
|
|
473 |
||
9443.2.2
by Abel Deuring
implemented reviewer's comments |
474 |
:return: A list of dictionaries, where each dictionary
|
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
475 |
describes a udev device.
|
476 |
||
477 |
The <udev> node contains the output produced by
|
|
478 |
"udevadm info --export-db". Each entry of the dictionaries
|
|
479 |
represents the data of the key:value pairs as they appear
|
|
480 |
in this data. The value of d['S'] is a list of strings,
|
|
481 |
the value s['E'] is a dictionary containing the key=value
|
|
482 |
pairs of the "E:" lines.
|
|
483 |
"""
|
|
484 |
# We get the plain text as produced by "udevadm info --export-db"
|
|
485 |
# This data looks like:
|
|
486 |
#
|
|
487 |
# P: /devices/LNXSYSTM:00
|
|
488 |
# E: UDEV_LOG=3
|
|
489 |
# E: DEVPATH=/devices/LNXSYSTM:00
|
|
490 |
# E: MODALIAS=acpi:LNXSYSTM:
|
|
491 |
#
|
|
492 |
# P: /devices/LNXSYSTM:00/ACPI_CPU:00
|
|
493 |
# E: UDEV_LOG=3
|
|
494 |
# E: DEVPATH=/devices/LNXSYSTM:00/ACPI_CPU:00
|
|
495 |
# E: DRIVER=processor
|
|
496 |
# E: MODALIAS=acpi:ACPI_CPU:
|
|
497 |
#
|
|
498 |
# Data for different devices is separated by empty lines.
|
|
499 |
# Each line for a device consists of key:value pairs.
|
|
500 |
# The following keys are defined:
|
|
501 |
#
|
|
502 |
# A: udev_device_get_num_fake_partitions()
|
|
503 |
# E: udev_device_get_properties_list_entry()
|
|
504 |
# L: the device link priority (udev_device_get_devlink_priority())
|
|
505 |
# N: the device node file name (udev_device_get_devnode())
|
|
506 |
# P: the device path (udev_device_get_devpath())
|
|
507 |
# R: udev_device_get_ignore_remove()
|
|
508 |
# S: udev_get_dev_path()
|
|
509 |
# W: udev_device_get_watch_handle()
|
|
510 |
#
|
|
511 |
# The key P is always present; the keys A, L, N, R, W appear at
|
|
512 |
# most once per device; the keys E and S may appear more than
|
|
513 |
# once.
|
|
514 |
# The values of the E records have the format "key=value"
|
|
515 |
#
|
|
516 |
# See also the libudev reference manual:
|
|
517 |
# http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
|
|
518 |
# and the udev file udevadm-info.c, function print_record()
|
|
519 |
||
520 |
udev_data = udev_node.text.split('\n') |
|
521 |
devices = [] |
|
522 |
device = None |
|
523 |
line_number = 0 |
|
9747.1.1
by Abel Deuring
Property UdevDevice.id added |
524 |
device_id = 0 |
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
525 |
|
9443.2.2
by Abel Deuring
implemented reviewer's comments |
526 |
for line_number, line in enumerate(udev_data): |
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
527 |
if len(line) == 0: |
528 |
device = None |
|
529 |
continue
|
|
530 |
record = line.split(':', 1) |
|
531 |
if len(record) != 2: |
|
532 |
self._logError( |
|
533 |
'Line %i in <udev>: No valid key:value data: %r' |
|
534 |
% (line_number, line), |
|
535 |
self.submission_key) |
|
536 |
return None |
|
537 |
||
538 |
key, value = record |
|
539 |
if device is None: |
|
9747.1.1
by Abel Deuring
Property UdevDevice.id added |
540 |
device_id += 1 |
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
541 |
device = { |
542 |
'E': {}, |
|
543 |
'S': [], |
|
9747.1.1
by Abel Deuring
Property UdevDevice.id added |
544 |
'id': device_id, |
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
545 |
}
|
546 |
devices.append(device) |
|
547 |
# Some attribute lines have a space character after the
|
|
548 |
# ':', others don't have it (see udevadm-info.c).
|
|
549 |
value = value.lstrip() |
|
550 |
||
551 |
if key == 'E': |
|
552 |
property_data = value.split('=', 1) |
|
553 |
if len(property_data) != 2: |
|
554 |
self._logError( |
|
555 |
'Line %i in <udev>: Property without valid key=value ' |
|
556 |
'data: %r' % (line_number, line), |
|
557 |
self.submission_key) |
|
558 |
return None |
|
559 |
property_key, property_value = property_data |
|
560 |
device['E'][property_key] = property_value |
|
561 |
elif key == 'S': |
|
562 |
device['S'].append(value) |
|
563 |
else: |
|
564 |
if key in device: |
|
565 |
self._logWarning( |
|
566 |
'Line %i in <udev>: Duplicate attribute key: %r' |
|
567 |
% (line_number, line), |
|
568 |
self.submission_key) |
|
569 |
device[key] = value |
|
570 |
return devices |
|
7844.3.2
by Abel Deuring
fine adjustment to the changes to exactly match the previous version |
571 |
|
9580.2.1
by Abel Deuring
method HWSubmissionParser._parseDmi() added |
572 |
def _parseDmi(self, dmi_node): |
573 |
"""Parse the <dmi> node.
|
|
574 |
||
575 |
:return: A dictionary containing the key:value pairs of the DMI data.
|
|
576 |
"""
|
|
577 |
dmi_data = {} |
|
578 |
dmi_text = dmi_node.text.strip().split('\n') |
|
579 |
for line_number, line in enumerate(dmi_text): |
|
580 |
record = line.split(':', 1) |
|
581 |
if len(record) != 2: |
|
582 |
self._logError( |
|
583 |
'Line %i in <dmi>: No valid key:value data: %r' |
|
584 |
% (line_number, line), |
|
585 |
self.submission_key) |
|
586 |
return None |
|
587 |
dmi_data[record[0]] = record[1] |
|
588 |
return dmi_data |
|
589 |
||
9580.6.1
by Abel Deuring
method SubmissionParser._parseSysfsAttributes() added |
590 |
def _parseSysfsAttributes(self, sysfs_node): |
591 |
"""Parse the <sysfs-attributes> node.
|
|
592 |
||
593 |
:return: A dictionary {path: attrs, ...} where path is the
|
|
594 |
path is the path of a sysfs directory, and where attrs
|
|
595 |
is a dictionary containing attribute names and values.
|
|
596 |
||
597 |
A sample of the input data:
|
|
598 |
||
599 |
P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
|
|
600 |
A: modalias=input:b0019v0000p0001e0000-e0,1,k74,ramlsfw
|
|
601 |
A: uniq=
|
|
602 |
A: phys=LNXPWRBN/button/input0
|
|
603 |
A: name=Power Button
|
|
604 |
||
605 |
P: /devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03/input/input8
|
|
606 |
A: modalias=input:b0019v0000p0006e0000-e0,1,kE0,E1,E3,F0,F1
|
|
607 |
A: uniq=
|
|
608 |
A: phys=/video/input0
|
|
609 |
A: name=Video Bus
|
|
610 |
||
611 |
Data for different devices is separated by empty lines. The data
|
|
612 |
for each device starts with a line 'P: /devices/LNXSYSTM...',
|
|
613 |
specifying the sysfs path of a device, followed by zero or more
|
|
614 |
lines of the form 'A: key=value'
|
|
615 |
"""
|
|
616 |
sysfs_lines = sysfs_node.text.split('\n') |
|
617 |
sysfs_data = {} |
|
618 |
attributes = None |
|
619 |
||
620 |
for line_number, line in enumerate(sysfs_lines): |
|
621 |
if len(line) == 0: |
|
622 |
attributes = None |
|
623 |
continue
|
|
624 |
record = line.split(': ', 1) |
|
625 |
if len(record) != 2: |
|
626 |
self._logError( |
|
627 |
'Line %i in <sysfs-attributes>: No valid key:value data: ' |
|
628 |
'%r' % (line_number, line), |
|
629 |
self.submission_key) |
|
630 |
return None |
|
631 |
||
632 |
key, value = record |
|
633 |
if key == 'P': |
|
634 |
if attributes is not None: |
|
635 |
self._logError( |
|
636 |
"Line %i in <sysfs-attributes>: duplicate 'P' line " |
|
637 |
"found: %r" % (line_number, line), |
|
638 |
self.submission_key) |
|
639 |
return None |
|
640 |
attributes = {} |
|
641 |
sysfs_data[value] = attributes |
|
642 |
elif key == 'A': |
|
643 |
if attributes is None: |
|
644 |
self._logError( |
|
645 |
"Line %i in <sysfs-attributes>: Block for a device " |
|
646 |
"does not start with 'P:': %r" % (line_number, line), |
|
647 |
self.submission_key) |
|
648 |
return None |
|
649 |
attribute_data = value.split('=', 1) |
|
650 |
if len(attribute_data) != 2: |
|
651 |
self._logError( |
|
652 |
'Line %i in <sysfs-attributes>: Attribute line does ' |
|
653 |
'not contain key=value data: %r' |
|
654 |
% (line_number, line), |
|
655 |
self.submission_key) |
|
656 |
return None |
|
657 |
attributes[attribute_data[0]] = attribute_data[1] |
|
658 |
else: |
|
659 |
self._logError( |
|
660 |
'Line %i in <sysfs-attributes>: Unexpected key: %r' |
|
661 |
% (line_number, line), |
|
662 |
self.submission_key) |
|
663 |
return None |
|
664 |
return sysfs_data |
|
665 |
||
5628.8.3
by Abel Deuring
implemented reviewer's comments |
666 |
def _setHardwareSectionParsers(self): |
667 |
self._parse_hardware_section = { |
|
668 |
'hal': self._parseHAL, |
|
669 |
'processors': self._parseProcessors, |
|
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
670 |
'aliases': self._parseAliases, |
671 |
'udev': self._parseUdev, |
|
9580.2.1
by Abel Deuring
method HWSubmissionParser._parseDmi() added |
672 |
'dmi': self._parseDmi, |
9580.6.1
by Abel Deuring
method SubmissionParser._parseSysfsAttributes() added |
673 |
'sysfs-attributes': self._parseSysfsAttributes, |
9443.2.1
by Abel Deuring
parse content of the <udev> mode in HWDB submissions |
674 |
}
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
675 |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
676 |
def _parseHardware(self, hardware_node): |
677 |
"""Parse the <hardware> part of a submission.
|
|
678 |
||
679 |
:return: A dictionary with the keys 'hal', 'processors', 'aliases',
|
|
680 |
where the values are the parsing results of _parseHAL,
|
|
681 |
_parseProcessors, _parseAliases.
|
|
682 |
"""
|
|
683 |
hardware_data = {} |
|
684 |
for node in hardware_node.getchildren(): |
|
685 |
parser = self._parse_hardware_section[node.tag] |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
686 |
result = parser(node) |
9747.1.13
by Abel Deuring
propagate errros ocurring in SubmissionParser.parseHardware() up the call chain |
687 |
if result is None: |
688 |
return None |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
689 |
hardware_data[node.tag] = result |
690 |
return hardware_data |
|
691 |
||
692 |
def _parseLSBRelease(self, lsb_node): |
|
693 |
"""Parse the <lsb_release> part of a submission.
|
|
694 |
||
695 |
:return: A dictionary with the content of the <properta> nodes
|
|
696 |
within the <lsb> node. See tests/hardwaretest.xml for
|
|
697 |
details.
|
|
698 |
"""
|
|
699 |
return self._parseProperties(lsb_node) |
|
700 |
||
701 |
def _parsePackages(self, packages_node): |
|
702 |
"""Parse the <packages> part of a submission.
|
|
703 |
||
704 |
:return: A dictionary with one entry per <package> sub-node.
|
|
705 |
The key is the package name, the value a dictionary
|
|
706 |
containing the content of the <property> nodes within
|
|
707 |
<package>. See tests/hardwaretest.xml for more details.
|
|
708 |
"""
|
|
709 |
packages = {} |
|
710 |
for package_node in packages_node.getchildren(): |
|
711 |
# Pure paranoia: The Relax NG validation ensures already
|
|
712 |
# that we have only <package> tags within <packages>.
|
|
713 |
assert package_node.tag == 'package', ( |
|
714 |
'Parsing submission %s: Unexpected tag <%s> in <packages>' |
|
715 |
% (self.submission_key, package_node.tag)) |
|
716 |
package_name = package_node.get('name') |
|
717 |
if package_name in packages.keys(): |
|
718 |
raise ValueError( |
|
719 |
'<package name="%s"> appears more than once in <packages>' |
|
720 |
% package_name) |
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
721 |
# The RelaxNG validation ensures that the attribute "id" exists
|
722 |
# and that it contains an integer.
|
|
723 |
package_data = {'id': int(package_node.get('id'))} |
|
724 |
package_data['properties'] = self._parseProperties(package_node) |
|
725 |
packages[package_name] = package_data |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
726 |
return packages |
727 |
||
728 |
def _parseXOrg(self, xorg_node): |
|
729 |
"""Parse the <xorg> part of a submission.
|
|
730 |
||
731 |
:return: A dictionary with the keys 'version' and 'drivers'.
|
|
732 |
d['version'] is the xorg version; d['drivers'] is
|
|
733 |
a dictionary with one entry for each <driver> sub-node,
|
|
734 |
where the key is the driver name, the value is a dictionary
|
|
735 |
containing the attributes of the <driver> node. See
|
|
736 |
tests/hardwaretest.xml for more details.
|
|
737 |
"""
|
|
738 |
xorg_data = {'version': xorg_node.get('version')} |
|
739 |
xorg_data['drivers'] = xorg_drivers = {} |
|
740 |
for driver_node in xorg_node.getchildren(): |
|
741 |
# Pure paranoia: The Relax NG validation ensures already
|
|
742 |
# that we have only <driver> tags within <xorg>.
|
|
743 |
assert driver_node.tag == 'driver', ( |
|
744 |
'Parsing submission %s: Unexpected tag <%s> in <xorg>' |
|
745 |
% (self.submission_key, driver_node.tag)) |
|
746 |
driver_info = dict(driver_node.attrib) |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
747 |
if 'device' in driver_info: |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
748 |
# The Relax NG validation ensures that driver_info['device']
|
749 |
# consists of only digits, if present.
|
|
750 |
driver_info['device'] = int(driver_info['device']) |
|
751 |
driver_name = driver_info['name'] |
|
752 |
if driver_name in xorg_drivers.keys(): |
|
753 |
raise ValueError( |
|
754 |
'<driver name="%s"> appears more than once in <xorg>' |
|
755 |
% driver_name) |
|
756 |
xorg_drivers[driver_name] = driver_info |
|
757 |
return xorg_data |
|
758 |
||
759 |
_parse_software_section = { |
|
760 |
'lsbrelease': _parseLSBRelease, |
|
761 |
'packages': _parsePackages, |
|
762 |
'xorg': _parseXOrg} |
|
763 |
||
5628.8.3
by Abel Deuring
implemented reviewer's comments |
764 |
def _setSoftwareSectionParsers(self): |
765 |
self._parse_software_section = { |
|
766 |
'lsbrelease': self._parseLSBRelease, |
|
767 |
'packages': self._parsePackages, |
|
768 |
'xorg': self._parseXOrg} |
|
769 |
||
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
770 |
def _parseSoftware(self, software_node): |
771 |
"""Parse the <software> section of a submission.
|
|
772 |
||
773 |
:return: A dictionary with the keys 'lsbrelease', 'packages',
|
|
774 |
'xorg', containing the parsing results of the respective
|
|
775 |
sub-nodes. The key 'lsbrelease' exists always; 'xorg'
|
|
776 |
and 'packages' are optional. See _parseLSBRelease,
|
|
777 |
_parsePackages, _parseXOrg for more details.
|
|
778 |
"""
|
|
779 |
software_data = {} |
|
780 |
for node in software_node.getchildren(): |
|
781 |
parser = self._parse_software_section[node.tag] |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
782 |
result = parser(node) |
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
783 |
software_data[node.tag] = result |
7184.4.1
by Abel Deuring
ensure that the HWDB submission parser creates dummy data for the nodes <xorg> and <packages> if they do not appear in a submission. This fxies KeyErrors for submissions which do not contain these nodes |
784 |
# The nodes <packages> and <xorg> are optional. Ensure that
|
785 |
# we have dummy entries in software_data for these nodes, if
|
|
7184.4.2
by Abel Deuring
implemented reviewer's comments |
786 |
# the nodes do not appear in a submission in order to avoid
|
7184.4.1
by Abel Deuring
ensure that the HWDB submission parser creates dummy data for the nodes <xorg> and <packages> if they do not appear in a submission. This fxies KeyErrors for submissions which do not contain these nodes |
787 |
# KeyErrors elsewhere in this module.
|
788 |
for node_name in ('packages', 'xorg'): |
|
789 |
if node_name not in software_data: |
|
790 |
software_data[node_name] = {} |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
791 |
return software_data |
792 |
||
793 |
def _parseQuestions(self, questions_node): |
|
794 |
"""Parse the <questions> part of a submission.
|
|
795 |
||
796 |
:return: A list, where each entry is a dictionary containing
|
|
797 |
the parsing result of the <question> sub-nodes.
|
|
798 |
||
799 |
Content of a list entry d (see tests/hardwaretest.xml
|
|
800 |
for a more detailed description):
|
|
801 |
d['name']:
|
|
802 |
The name of a question. (Always present)
|
|
803 |
d['plugin']:
|
|
804 |
The name of the client plugin which is
|
|
805 |
"responsible" for the question. (Optional)
|
|
806 |
d['targets']:
|
|
807 |
A list, where each entry is a dicitionary
|
|
808 |
describing a target device for this question.
|
|
809 |
This list is always present, but may be empty.
|
|
810 |
||
811 |
The contents of each list entry t is:
|
|
812 |
||
813 |
t['id']:
|
|
814 |
The ID of a HAL <device> node of a
|
|
815 |
target device.
|
|
816 |
t['drivers']:
|
|
817 |
A list of driver names, possibly empty.
|
|
818 |
d['answer']:
|
|
819 |
The answer to this question. The value is a
|
|
820 |
dictionary a:
|
|
821 |
a['value']:
|
|
822 |
The value of the answer. (Always present)
|
|
823 |
||
824 |
For questions of type muliple_choice,
|
|
825 |
the value should match one of the
|
|
826 |
entries of the answer_choices list,
|
|
827 |
||
828 |
For questions of type measurement, the
|
|
829 |
value is a numerical value.
|
|
830 |
a['type']:
|
|
831 |
This is either 'multiple_choice' or
|
|
832 |
'measurement'. (Always present)
|
|
833 |
a['unit']:
|
|
834 |
The unit of a measurement value.
|
|
835 |
(Optional)
|
|
836 |
d['answer_choices']:
|
|
837 |
A list of choices from which the user can select
|
|
838 |
an answer. This list is always present, but should
|
|
839 |
be empty for questions of type measurement.
|
|
840 |
d['command']:
|
|
841 |
The command line of a test script which was
|
|
842 |
run for this question. (Optional)
|
|
843 |
d['comment']:
|
|
844 |
A comment the user has typed when running the
|
|
845 |
client. (Optional)
|
|
846 |
||
847 |
A consistency check of the content of d is done in
|
|
848 |
method _checkSubmissionConsistency.
|
|
849 |
"""
|
|
850 |
questions = [] |
|
851 |
for question_node in questions_node.getchildren(): |
|
852 |
# Pure paranoia: The Relax NG validation ensures already
|
|
853 |
# that we have only <driver> tags within <xorg>
|
|
854 |
assert question_node.tag == 'question', ( |
|
855 |
'Parsing submission %s: Unexpected tag <%s> in <questions>' |
|
856 |
% (self.submission_key, question_node.tag)) |
|
857 |
question = {'name': question_node.get('name')} |
|
858 |
plugin = question_node.get('plugin', None) |
|
859 |
if plugin is not None: |
|
860 |
question['plugin'] = plugin |
|
861 |
question['targets'] = targets = [] |
|
862 |
answer_choices = [] |
|
863 |
||
864 |
for sub_node in question_node.getchildren(): |
|
865 |
sub_tag = sub_node.tag |
|
866 |
if sub_tag == 'answer': |
|
867 |
question['answer'] = answer = {} |
|
868 |
answer['type'] = sub_node.get('type') |
|
869 |
if answer['type'] == 'multiple_choice': |
|
870 |
question['answer_choices'] = answer_choices |
|
871 |
unit = sub_node.get('unit', None) |
|
872 |
if unit is not None: |
|
873 |
answer['unit'] = unit |
|
874 |
answer['value'] = sub_node.text.strip() |
|
875 |
elif sub_tag == 'answer_choices': |
|
876 |
for value_node in sub_node.getchildren(): |
|
877 |
answer_choices.append( |
|
878 |
self._getValueAndType(value_node)) |
|
879 |
elif sub_tag == 'target': |
|
880 |
# The Relax NG schema ensures that the attribute
|
|
881 |
# id exists and that it is an integer
|
|
882 |
target = {'id': int(sub_node.get('id'))} |
|
883 |
target['drivers'] = drivers = [] |
|
884 |
for driver_node in sub_node.getchildren(): |
|
885 |
drivers.append(driver_node.text.strip()) |
|
886 |
targets.append(target) |
|
887 |
elif sub_tag in('comment', 'command'): |
|
888 |
data = sub_node.text |
|
889 |
if data is not None: |
|
890 |
question[sub_tag] = data.strip() |
|
891 |
else: |
|
892 |
# This should not happen: The Relax NG validation
|
|
893 |
# ensures that we have only those tags which appear
|
|
894 |
# in the if/elif expressions.
|
|
895 |
raise AssertionError( |
|
896 |
'Parsing submission %s: Unexpected node <%s> in ' |
|
897 |
'<question>' % (self.submission_key, sub_tag)) |
|
898 |
questions.append(question) |
|
899 |
return questions |
|
900 |
||
7844.3.3
by Abel Deuring
Nodes <context> and <info> added to the Relax NG schema for HWDB submissions. |
901 |
def _parseContext(self, context_node): |
902 |
"""Parse the <context> part of a submission.
|
|
903 |
||
904 |
We don't do anything real right now, but simply log a warning
|
|
905 |
that this submission contains a <context> section, so that
|
|
906 |
we can parse it again later, once we have the SQL tables needed
|
|
907 |
to store the data.
|
|
908 |
"""
|
|
909 |
self._logWarning('Submission contains unprocessed <context> data.') |
|
9747.1.13
by Abel Deuring
propagate errros ocurring in SubmissionParser.parseHardware() up the call chain |
910 |
return {} |
7844.3.3
by Abel Deuring
Nodes <context> and <info> added to the Relax NG schema for HWDB submissions. |
911 |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
912 |
def _setMainSectionParsers(self): |
913 |
self._parse_system = { |
|
914 |
'summary': self._parseSummary, |
|
915 |
'hardware': self._parseHardware, |
|
916 |
'software': self._parseSoftware, |
|
7844.3.3
by Abel Deuring
Nodes <context> and <info> added to the Relax NG schema for HWDB submissions. |
917 |
'questions': self._parseQuestions, |
918 |
'context': self._parseContext, |
|
919 |
}
|
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
920 |
|
921 |
def parseMainSections(self, submission_doc): |
|
922 |
# The RelaxNG validation ensures that submission_doc has exactly
|
|
923 |
# four sub-nodes and that the names of the sub-nodes appear in the
|
|
924 |
# keys of self._parse_system.
|
|
925 |
submission_data = {} |
|
926 |
try: |
|
927 |
for node in submission_doc.getchildren(): |
|
928 |
parser = self._parse_system[node.tag] |
|
9747.1.13
by Abel Deuring
propagate errros ocurring in SubmissionParser.parseHardware() up the call chain |
929 |
result = parser(node) |
930 |
if result is None: |
|
931 |
return None |
|
932 |
submission_data[node.tag] = result |
|
5628.8.3
by Abel Deuring
implemented reviewer's comments |
933 |
except ValueError, value: |
934 |
self._logError(value, self.submission_key) |
|
935 |
return None |
|
936 |
return submission_data |
|
5628.8.1
by Abel Deuring
create an internal representation of HWDB submissions |
937 |
|
938 |
def parseSubmission(self, submission, submission_key): |
|
939 |
"""Parse the data of a HWDB submission.
|
|
940 |
||
941 |
:return: A dictionary with the keys 'summary', 'hardware',
|
|
942 |
'software', 'questions'. See _parseSummary,
|
|
943 |
_parseHardware, _parseSoftware, _parseQuestions for
|
|
944 |
the content.
|
|
945 |
"""
|
|
946 |
self.submission_key = submission_key |
|
947 |
submission_doc = self._getValidatedEtree(submission, submission_key) |
|
948 |
if submission_doc is None: |
|
949 |
return None |
|
950 |
||
5628.8.3
by Abel Deuring
implemented reviewer's comments |
951 |
return self.parseMainSections(submission_doc) |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
952 |
|
953 |
def _findDuplicates(self, all_ids, test_ids): |
|
954 |
"""Search for duplicate elements in test_ids.
|
|
955 |
||
956 |
:return: A set of those elements in the sequence test_ids that
|
|
957 |
are elements of the set all_ids or that appear more than once
|
|
958 |
in test_ids.
|
|
959 |
||
960 |
all_ids is updated with test_ids.
|
|
961 |
"""
|
|
962 |
duplicates = set() |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
963 |
# Note that test_ids itself may contain an ID more than once.
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
964 |
for test_id in test_ids: |
965 |
if test_id in all_ids: |
|
966 |
duplicates.add(test_id) |
|
967 |
else: |
|
968 |
all_ids.add(test_id) |
|
969 |
return duplicates |
|
970 |
||
971 |
def findDuplicateIDs(self, parsed_data): |
|
972 |
"""Return the set of duplicate IDs.
|
|
973 |
||
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
974 |
The IDs of devices, processors and software packages should be
|
975 |
unique; this method returns a list of duplicate IDs found in a
|
|
976 |
submission.
|
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
977 |
"""
|
978 |
all_ids = set() |
|
9637.2.1
by Abel Deuring
consistency checks for HWDDB submissions with udev data |
979 |
if 'hal' in parsed_data['hardware']: |
980 |
duplicates = self._findDuplicates( |
|
981 |
all_ids, |
|
982 |
[device['id'] |
|
983 |
for device in parsed_data['hardware']['hal']['devices']]) |
|
984 |
else: |
|
985 |
duplicates = self._findDuplicates( |
|
986 |
all_ids, |
|
987 |
[device['P'] |
|
988 |
for device in parsed_data['hardware']['udev']]) |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
989 |
duplicates.update(self._findDuplicates( |
990 |
all_ids, |
|
991 |
[processor['id'] |
|
992 |
for processor in parsed_data['hardware']['processors']])) |
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
993 |
duplicates.update(self._findDuplicates( |
994 |
all_ids, |
|
995 |
[package['id'] |
|
996 |
for package in parsed_data['software']['packages'].values()])) |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
997 |
return duplicates |
998 |
||
999 |
def _getIDMap(self, parsed_data): |
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
1000 |
"""Return a dictionary ID -> devices, processors and packages."""
|
1001 |
id_map = {} |
|
9637.2.1
by Abel Deuring
consistency checks for HWDDB submissions with udev data |
1002 |
if 'hal' in parsed_data['hardware']: |
1003 |
hal_devices = parsed_data['hardware']['hal']['devices'] |
|
1004 |
for device in hal_devices: |
|
1005 |
id_map[device['id']] = device |
|
1006 |
else: |
|
1007 |
udev_devices = parsed_data['hardware']['udev'] |
|
1008 |
for device in udev_devices: |
|
1009 |
id_map[device['P']] = device |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1010 |
|
1011 |
for processor in parsed_data['hardware']['processors']: |
|
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
1012 |
id_map[processor['id']] = processor |
1013 |
||
1014 |
for package in parsed_data['software']['packages'].values(): |
|
1015 |
id_map[package['id']] = package |
|
1016 |
||
1017 |
return id_map |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1018 |
|
1019 |
def findInvalidIDReferences(self, parsed_data): |
|
1020 |
"""Return the set of invalid references to IDs.
|
|
1021 |
||
5915.3.1
by Abel Deuring
HWDB Relax NG schema modification: stricter rules for IDs; missing attribute 'id' for <package> added |
1022 |
The sub-tag <target> of <question> references a device, processor
|
1023 |
of package node by its ID; the submission must contain a <device>,
|
|
1024 |
<processor> or <software> tag with this ID. This method returns a
|
|
1025 |
set of those IDs mentioned in <target> nodes that have no
|
|
1026 |
corresponding device or processor node.
|
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1027 |
"""
|
1028 |
id_device_map = self._getIDMap(parsed_data) |
|
1029 |
known_ids = set(id_device_map.keys()) |
|
1030 |
questions = parsed_data['questions'] |
|
1031 |
target_lists = [question['targets'] for question in questions] |
|
1032 |
all_targets = [] |
|
1033 |
for target_list in target_lists: |
|
1034 |
all_targets.extend(target_list) |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1035 |
all_target_ids = set(target['id'] for target in all_targets) |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1036 |
return all_target_ids.difference(known_ids) |
1037 |
||
1038 |
def getUDIDeviceMap(self, devices): |
|
1039 |
"""Return a dictionary which maps UDIs to HAL devices.
|
|
1040 |
||
8294.5.1
by Abel Deuring
Fix for bug 336613: ignore certain duplicate UDIs in HWDB submissions |
1041 |
Also check, if a UDI is used more than once.
|
1042 |
||
1043 |
Generally, a duplicate UDI indicates a bad or bogus submission,
|
|
1044 |
but we have some UDIs where the duplicate UDI is caused by a
|
|
1045 |
bug in HAL, see
|
|
1046 |
http://lists.freedesktop.org/archives/hal/2009-April/013250.html
|
|
1047 |
In these cases, we simply remove the duplicates, otherwise, a
|
|
1048 |
ValueError is raised.
|
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1049 |
"""
|
1050 |
udi_device_map = {} |
|
8294.5.1
by Abel Deuring
Fix for bug 336613: ignore certain duplicate UDIs in HWDB submissions |
1051 |
duplicates = [] |
1052 |
for index in xrange(len(devices)): |
|
1053 |
device = devices[index] |
|
1054 |
udi = device['udi'] |
|
1055 |
if udi in udi_device_map: |
|
1056 |
if 'info.parent' in device['properties']: |
|
1057 |
parent_udi = device['properties']['info.parent'][0] |
|
1058 |
else: |
|
1059 |
parent_udi = None |
|
1060 |
if (udi in KNOWN_DUPLICATE_UDIS or |
|
1061 |
parent_udi in KNOWN_DUPLICATE_UDIS): |
|
1062 |
duplicates.append(index) |
|
1063 |
continue
|
|
1064 |
else: |
|
1065 |
raise ValueError('Duplicate UDI: %s' % device['udi']) |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1066 |
else: |
8294.5.1
by Abel Deuring
Fix for bug 336613: ignore certain duplicate UDIs in HWDB submissions |
1067 |
udi_device_map[udi] = device |
1068 |
duplicates.reverse() |
|
1069 |
for index in duplicates: |
|
1070 |
devices.pop(index) |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1071 |
return udi_device_map |
1072 |
||
1073 |
def _getIDUDIMaps(self, devices): |
|
1074 |
"""Return two mappings describing the relation between IDs and UDIs.
|
|
1075 |
||
1076 |
:return: two dictionaries id_to_udi and udi_to_id, where
|
|
1077 |
id_2_udi has IDs as keys and UDI as values, and where
|
|
1078 |
udi_to_id has UDIs as keys and IDs as values.
|
|
1079 |
"""
|
|
1080 |
id_to_udi = {} |
|
1081 |
udi_to_id = {} |
|
1082 |
for device in devices: |
|
1083 |
id = device['id'] |
|
1084 |
udi = device['udi'] |
|
1085 |
id_to_udi[id] = udi |
|
1086 |
udi_to_id[udi] = id |
|
1087 |
return id_to_udi, udi_to_id |
|
1088 |
||
1089 |
def getUDIChildren(self, udi_device_map): |
|
1090 |
"""Build lists of all children of a UDI.
|
|
1091 |
||
1092 |
:return: A dictionary that maps UDIs to lists of children.
|
|
1093 |
||
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1094 |
If any info.parent property points to a non-existing existing
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1095 |
device, a ValueError is raised.
|
1096 |
"""
|
|
1097 |
# Each HAL device references its parent device (HAL attribute
|
|
1098 |
# info.parent), except for the "root node", which has no parent.
|
|
1099 |
children = {} |
|
1100 |
known_udis = set(udi_device_map.keys()) |
|
1101 |
for device in udi_device_map.values(): |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1102 |
parent_property = device['properties'].get('info.parent', None) |
1103 |
if parent_property is not None: |
|
1104 |
parent = parent_property[0] |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1105 |
if not parent in known_udis: |
1106 |
raise ValueError( |
|
1107 |
'Unknown parent UDI %s in <device id="%s">' |
|
1108 |
% (parent, device['id'])) |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1109 |
if parent in children: |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1110 |
children[parent].append(device) |
1111 |
else: |
|
1112 |
children[parent] = [device] |
|
1113 |
else: |
|
1114 |
# A node without a parent is a root node. Only one root node
|
|
1115 |
# is allowed, which must have the UDI
|
|
1116 |
# "/org/freedesktop/Hal/devices/computer".
|
|
1117 |
# Other nodes without a parent UDI indicate an error, as well
|
|
1118 |
# as a non-existing root node.
|
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1119 |
if device['udi'] != ROOT_UDI: |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1120 |
raise ValueError( |
1121 |
'root device node found with unexpected UDI: '
|
|
1122 |
'<device id="%s" udi="%s">' % (device['id'], |
|
1123 |
device['udi'])) |
|
1124 |
||
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1125 |
if not ROOT_UDI in children: |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1126 |
raise ValueError('No root device found') |
1127 |
return children |
|
1128 |
||
1129 |
def _removeChildren(self, udi, udi_test): |
|
1130 |
"""Remove recursively all children of the device named udi."""
|
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1131 |
if udi in udi_test: |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1132 |
children = udi_test[udi] |
1133 |
for child in children: |
|
1134 |
self._removeChildren(child['udi'], udi_test) |
|
1135 |
del udi_test[udi] |
|
1136 |
||
1137 |
def checkHALDevicesParentChildConsistency(self, udi_children): |
|
1138 |
"""Ensure that HAL devices are represented in exactly one tree.
|
|
1139 |
||
1140 |
:return: A list of those UDIs that are not "connected" to the root
|
|
1141 |
node /org/freedesktop/Hal/devices/computer
|
|
1142 |
||
1143 |
HAL devices "know" their parent device; each device has a parent,
|
|
1144 |
except the root element. This means that it is possible to traverse
|
|
1145 |
all existing devices, beginning at the root node.
|
|
1146 |
||
1147 |
Several inconsistencies are possible:
|
|
1148 |
||
1149 |
(a) we may have more than one root device (i.e., one without a
|
|
1150 |
parent)
|
|
1151 |
(b) we may have no root element
|
|
1152 |
(c) circular parent/child references may exist.
|
|
1153 |
||
1154 |
(a) and (b) are already checked in _getUDIChildren; this method
|
|
1155 |
implements (c),
|
|
1156 |
"""
|
|
1157 |
# If we build a copy of udi_children and if we remove, starting at
|
|
1158 |
# the root UDI, recursively all children from this copy, we should
|
|
1159 |
# get a dictionary, where all values are empty lists. Any remaining
|
|
1160 |
# nodes must have circular parent references.
|
|
1161 |
||
1162 |
udi_test = {} |
|
1163 |
for udi, children in udi_children.items(): |
|
1164 |
udi_test[udi] = children[:] |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1165 |
self._removeChildren(ROOT_UDI, udi_test) |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1166 |
return udi_test.keys() |
1167 |
||
9637.2.1
by Abel Deuring
consistency checks for HWDDB submissions with udev data |
1168 |
def checkUdevDictsHavePathKey(self, udev_nodes): |
1169 |
"""Ensure that each udev dictionary has a 'P' key.
|
|
1170 |
||
1171 |
The 'P' (path) key identifies a device.
|
|
1172 |
"""
|
|
1173 |
for node in udev_nodes: |
|
1174 |
if not 'P' in node: |
|
1175 |
self._logError('udev node found without a "P" key', |
|
1176 |
self.submission_key) |
|
1177 |
return False |
|
1178 |
return True |
|
1179 |
||
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1180 |
PCI_PROPERTIES = set( |
1181 |
('PCI_CLASS', 'PCI_ID', 'PCI_SUBSYS_ID', 'PCI_SLOT_NAME')) |
|
1182 |
pci_class_re = re.compile('^[0-9a-f]{1,6}$', re.I) |
|
1183 |
pci_id_re = re.compile('^[0-9a-f]{4}:[0-9a-f]{4}$', re.I) |
|
1184 |
||
1185 |
def checkUdevPciProperties(self, udev_data): |
|
1186 |
"""Validation of udev PCI devices.
|
|
1187 |
||
9644.3.6
by Abel Deuring
implemented reviewer's comments |
1188 |
:param udev_data: A list of dicitionaries describing udev
|
1189 |
devices, as returned by _parseUdev()
|
|
1190 |
:return: True if all checks pass, else False.
|
|
1191 |
||
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1192 |
Each PCI device must have the properties PCI_CLASS, PCI_ID,
|
1193 |
PCI_SUBSYS_ID, PCI_SLOT_NAME. Non-PCI devices must not have
|
|
1194 |
them.
|
|
1195 |
||
1196 |
The value of PCI class must be a 24 bit integer in
|
|
1197 |
hexadecimal representation.
|
|
1198 |
||
1199 |
The values of PCI_ID and PCI_SUBSYS_ID must be two 16 bit
|
|
1200 |
integers, separated by a ':'.
|
|
1201 |
"""
|
|
1202 |
for device in udev_data: |
|
1203 |
properties = device['E'] |
|
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1204 |
property_names = set(properties) |
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1205 |
existing_pci_properties = property_names.intersection( |
1206 |
self.PCI_PROPERTIES) |
|
1207 |
subsystem = device['E'].get('SUBSYSTEM') |
|
1208 |
if subsystem is None: |
|
1209 |
self._logError( |
|
1210 |
'udev device without SUBSYSTEM property found.', |
|
1211 |
self.submission_key) |
|
1212 |
return False |
|
1213 |
if subsystem == 'pci': |
|
9644.3.6
by Abel Deuring
implemented reviewer's comments |
1214 |
# Check whether any of the standard pci properties were
|
1215 |
# missing.
|
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1216 |
if existing_pci_properties != self.PCI_PROPERTIES: |
9644.3.3
by Abel Deuring
improved tests for udev sanity checks |
1217 |
missing_properties = self.PCI_PROPERTIES.difference( |
1218 |
existing_pci_properties) |
|
1219 |
||
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1220 |
self._logError( |
9644.3.3
by Abel Deuring
improved tests for udev sanity checks |
1221 |
'PCI udev device without required PCI properties: '
|
1222 |
'%r %r' |
|
1223 |
% (missing_properties, device['P']), |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1224 |
self.submission_key) |
1225 |
return False |
|
9644.3.6
by Abel Deuring
implemented reviewer's comments |
1226 |
# Ensure that the pci class and ids for this device are
|
1227 |
# formally valid.
|
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1228 |
if self.pci_class_re.search(properties['PCI_CLASS']) is None: |
1229 |
self._logError( |
|
9644.3.3
by Abel Deuring
improved tests for udev sanity checks |
1230 |
'Invalid udev PCI class: %r %r' |
1231 |
% (properties['PCI_CLASS'], device['P']), |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1232 |
self.submission_key) |
1233 |
return False |
|
1234 |
for pci_id in (properties['PCI_ID'], |
|
1235 |
properties['PCI_SUBSYS_ID']): |
|
1236 |
if self.pci_id_re.search(pci_id) is None: |
|
1237 |
self._logError( |
|
9644.3.3
by Abel Deuring
improved tests for udev sanity checks |
1238 |
'Invalid udev PCI device ID: %r %r' |
1239 |
% (pci_id, device['P']), |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1240 |
self.submission_key) |
1241 |
return False |
|
1242 |
else: |
|
1243 |
if len(existing_pci_properties) > 0: |
|
1244 |
self._logError( |
|
9644.3.3
by Abel Deuring
improved tests for udev sanity checks |
1245 |
'Non-PCI udev device with PCI properties: %r %r' |
1246 |
% (existing_pci_properties, device['P']), |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1247 |
self.submission_key) |
1248 |
return False |
|
9644.3.3
by Abel Deuring
improved tests for udev sanity checks |
1249 |
return True |
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1250 |
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1251 |
def checkUdevUsbProperties(self, udev_data): |
1252 |
"""Validation of udev USB devices.
|
|
1253 |
||
9747.1.9
by Abel Deuring
validate nodes for USB devices in HWDB submissions with udev data that do not have the properties DEVTYPE, PRODUCT, TYPE |
1254 |
USB devices must either have the three properties DEVTYPE
|
1255 |
(value 'usb_device' or 'usb_interface'), PRODUCT and TYPE,
|
|
1256 |
or they must have none of them.
|
|
1257 |
||
1258 |
PRODUCT must be a tuple of three integers in hexadecimal
|
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1259 |
representation, separates by '/'. TYPE must be a a tuple of
|
1260 |
three integers in decimal representation, separated by '/'.
|
|
1261 |
usb_interface nodes must additionally have a property
|
|
1262 |
INTERFACE, containing three integers in the same format as
|
|
1263 |
TYPE.
|
|
1264 |
"""
|
|
1265 |
for device in udev_data: |
|
1266 |
subsystem = device['E'].get('SUBSYSTEM') |
|
1267 |
if subsystem != 'usb': |
|
1268 |
continue
|
|
1269 |
properties = device['E'] |
|
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1270 |
property_names = set(properties) |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1271 |
existing_usb_properties = property_names.intersection( |
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1272 |
UDEV_USB_DEVICE_PROPERTIES) |
9747.1.9
by Abel Deuring
validate nodes for USB devices in HWDB submissions with udev data that do not have the properties DEVTYPE, PRODUCT, TYPE |
1273 |
|
1274 |
if len(existing_usb_properties) == 0: |
|
1275 |
continue
|
|
1276 |
||
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1277 |
if existing_usb_properties != UDEV_USB_DEVICE_PROPERTIES: |
1278 |
missing_properties = UDEV_USB_DEVICE_PROPERTIES.difference( |
|
1279 |
existing_usb_properties) |
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1280 |
self._logError( |
1281 |
'USB udev device found without required properties: %r %r' |
|
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1282 |
% (missing_properties, device['P']), |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1283 |
self.submission_key) |
1284 |
return False |
|
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1285 |
if UDEV_USB_PRODUCT_RE.search(properties['PRODUCT']) is None: |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1286 |
self._logError( |
1287 |
'USB udev device found with invalid product ID: %r %r' |
|
1288 |
% (properties['PRODUCT'], device['P']), |
|
1289 |
self.submission_key) |
|
1290 |
return False |
|
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1291 |
if UDEV_USB_TYPE_RE.search(properties['TYPE']) is None: |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1292 |
self._logError( |
1293 |
'USB udev device found with invalid type data: %r %r' |
|
1294 |
% (properties['TYPE'], device['P']), |
|
1295 |
self.submission_key) |
|
1296 |
return False |
|
1297 |
||
1298 |
device_type = properties['DEVTYPE'] |
|
1299 |
if device_type not in ('usb_device', 'usb_interface'): |
|
1300 |
self._logError( |
|
1301 |
'USB udev device found with invalid udev type data: %r %r' |
|
1302 |
% (device_type, device['P']), |
|
1303 |
self.submission_key) |
|
1304 |
return False |
|
1305 |
if device_type == 'usb_interface': |
|
1306 |
interface_type = properties.get('INTERFACE') |
|
1307 |
if interface_type is None: |
|
1308 |
self._logError( |
|
1309 |
'USB interface udev device found without INTERFACE '
|
|
1310 |
'property: %r' |
|
1311 |
% device['P'], |
|
1312 |
self.submission_key) |
|
1313 |
return False |
|
9644.3.8
by Abel Deuring
implemented reviewer's comments |
1314 |
if UDEV_USB_TYPE_RE.search(interface_type) is None: |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1315 |
self._logError( |
1316 |
'USB Interface udev device found with invalid '
|
|
1317 |
'INTERFACE property: %r %r' |
|
1318 |
% (interface_type, device['P']), |
|
1319 |
self.submission_key) |
|
1320 |
return False |
|
1321 |
return True |
|
1322 |
||
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
1323 |
def checkUdevScsiProperties(self, udev_data, sysfs_data): |
1324 |
"""Validation of udev SCSI devices.
|
|
1325 |
||
1326 |
Each udev node where SUBSYSTEM is 'scsi' should have the
|
|
1327 |
property DEVTYPE; nodes where DEVTYPE is 'scsi_device'
|
|
1328 |
should have a corresponding sysfs node, and this node should
|
|
1329 |
define the attributes 'vendor', 'model', 'type'.
|
|
1330 |
"""
|
|
1331 |
for device in udev_data: |
|
1332 |
subsystem = device['E'].get('SUBSYSTEM') |
|
1333 |
if subsystem != 'scsi': |
|
1334 |
continue
|
|
1335 |
properties = device['E'] |
|
1336 |
if 'DEVTYPE' not in properties: |
|
1337 |
self._logError( |
|
1338 |
'SCSI udev node found without DEVTYPE property: %r' |
|
1339 |
% device['P'], |
|
1340 |
self.submission_key) |
|
1341 |
return False |
|
1342 |
if properties['DEVTYPE'] == 'scsi_device': |
|
1343 |
device_path = device['P'] |
|
1344 |
if device_path not in sysfs_data: |
|
1345 |
self._logError( |
|
1346 |
'SCSI udev device node found without related '
|
|
1347 |
'sysfs record: %r' % device_path, |
|
1348 |
self.submission_key) |
|
1349 |
return False |
|
1350 |
sysfs_attributes = sysfs_data[device_path] |
|
1351 |
sysfs_attribute_names = set(sysfs_attributes) |
|
1352 |
if SYSFS_SCSI_DEVICE_ATTRIBUTES.intersection( |
|
1353 |
sysfs_attribute_names) != SYSFS_SCSI_DEVICE_ATTRIBUTES: |
|
1354 |
missing_attributes = ( |
|
1355 |
SYSFS_SCSI_DEVICE_ATTRIBUTES.difference( |
|
1356 |
sysfs_attribute_names)) |
|
1357 |
self._logError( |
|
1358 |
'SCSI udev device found without required sysfs '
|
|
1359 |
'attributes: %r %r' |
|
1360 |
% (missing_attributes, device_path), |
|
1361 |
self.submission_key) |
|
1362 |
return False |
|
1363 |
return True |
|
1364 |
||
1365 |
def checkUdevDmiData(self, dmi_data): |
|
1366 |
"""Consistency check for DMI data.
|
|
1367 |
||
1368 |
All keys of the dictionary dmi_data should start with
|
|
1369 |
'/sys/class/dmi/id/'.
|
|
1370 |
"""
|
|
1371 |
for dmi_key in dmi_data: |
|
1372 |
if not dmi_key.startswith('/sys/class/dmi/id/'): |
|
1373 |
self._logError( |
|
1374 |
'Invalid DMI key: %r' % dmi_key, self.submission_key) |
|
1375 |
return False |
|
1376 |
return True |
|
1377 |
||
1378 |
def checkConsistentUdevDeviceData(self, udev_data, sysfs_data, dmi_data): |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1379 |
"""Consistency checks for udev data."""
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
1380 |
return ( |
1381 |
self.checkUdevDictsHavePathKey(udev_data) and |
|
1382 |
self.checkUdevPciProperties(udev_data) and |
|
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
1383 |
self.checkUdevUsbProperties(udev_data) and |
1384 |
self.checkUdevScsiProperties(udev_data, sysfs_data) and |
|
1385 |
self.checkUdevDmiData(dmi_data)) |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1386 |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1387 |
def checkConsistency(self, parsed_data): |
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1388 |
"""Run consistency checks on the submitted data.
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1389 |
|
5840.2.2
by Abel Deuring
implemented reviewer's comments |
1390 |
:return: True, if the data looks consistent, otherwise False.
|
1391 |
:param: parsed_data: parsed submission data, as returned by
|
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1392 |
parseSubmission
|
1393 |
"""
|
|
9644.3.2
by Abel Deuring
RF merge; conflicts resolved |
1394 |
if ('udev' in parsed_data['hardware'] |
1395 |
and not self.checkConsistentUdevDeviceData( |
|
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
1396 |
parsed_data['hardware']['udev'], |
9747.1.5
by Abel Deuring
Fixed a bad method call in the HWDB submission processing script; defined a new function validating method signatures in mock classes for testing; replaced monkey-patching of class SubmissionParser by mock classes in tests; validated the the mock classes with the new function. |
1397 |
parsed_data['hardware']['sysfs-attributes'], |
1398 |
parsed_data['hardware']['dmi'],)): |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
1399 |
return False |
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1400 |
duplicate_ids = self.findDuplicateIDs(parsed_data) |
1401 |
if duplicate_ids: |
|
1402 |
self._logError('Duplicate IDs found: %s' % duplicate_ids, |
|
1403 |
self.submission_key) |
|
1404 |
return False |
|
1405 |
||
1406 |
invalid_id_references = self.findInvalidIDReferences(parsed_data) |
|
1407 |
if invalid_id_references: |
|
1408 |
self._logError( |
|
1409 |
'Invalid ID references found: %s' % invalid_id_references, |
|
1410 |
self.submission_key) |
|
1411 |
return False |
|
1412 |
||
9637.2.1
by Abel Deuring
consistency checks for HWDDB submissions with udev data |
1413 |
if 'hal' in parsed_data['hardware']: |
1414 |
try: |
|
1415 |
udi_device_map = self.getUDIDeviceMap( |
|
1416 |
parsed_data['hardware']['hal']['devices']) |
|
1417 |
udi_children = self.getUDIChildren(udi_device_map) |
|
1418 |
except ValueError, value: |
|
1419 |
self._logError(value, self.submission_key) |
|
1420 |
return False |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1421 |
|
9644.3.4
by Abel Deuring
fixed a lint complaint about a too long line |
1422 |
circular = self.checkHALDevicesParentChildConsistency( |
1423 |
udi_children) |
|
9637.2.1
by Abel Deuring
consistency checks for HWDDB submissions with udev data |
1424 |
if circular: |
1425 |
self._logError('Found HAL devices with circular parent/child ' |
|
1426 |
'relationship: %s' % circular, |
|
1427 |
self.submission_key) |
|
1428 |
return False |
|
5840.2.1
by Abel Deuring
consistency checks for HWDB submissions |
1429 |
|
1430 |
return True |
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1431 |
|
1432 |
def buildDeviceList(self, parsed_data): |
|
1433 |
"""Create a list of devices from a submission."""
|
|
9710.4.7
by Abel Deuring
renamed SubmissionParser.buildDeviceList() to buildHalDeviceList(); new method buildDeviceList(); SubmissionParser.hal_devices renamed to SubmissionParser.devices |
1434 |
if 'hal' in parsed_data['hardware']: |
1435 |
return self.buildHalDeviceList(parsed_data) |
|
1436 |
else: |
|
1437 |
return self.buildUdevDeviceList(parsed_data) |
|
1438 |
||
1439 |
def buildHalDeviceList(self, parsed_data): |
|
1440 |
"""Create a list of devices from the HAL data of a submission."""
|
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1441 |
self.devices = {} |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1442 |
for hal_data in parsed_data['hardware']['hal']['devices']: |
1443 |
udi = hal_data['udi'] |
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1444 |
self.devices[udi] = HALDevice(hal_data['id'], udi, |
1445 |
hal_data['properties'], self) |
|
1446 |
for device in self.devices.values(): |
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1447 |
parent_udi = device.parent_udi |
1448 |
if parent_udi is not None: |
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1449 |
self.devices[parent_udi].addChild(device) |
9710.4.7
by Abel Deuring
renamed SubmissionParser.buildDeviceList() to buildHalDeviceList(); new method buildDeviceList(); SubmissionParser.hal_devices renamed to SubmissionParser.devices |
1450 |
return True |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1451 |
|
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1452 |
def buildUdevDeviceList(self, parsed_data): |
1453 |
"""Create a list of devices from the udev data of a submission."""
|
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1454 |
self.devices = {} |
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1455 |
sysfs_data = parsed_data['hardware']['sysfs-attributes'] |
1456 |
dmi_data = parsed_data['hardware']['dmi'] |
|
1457 |
for udev_data in parsed_data['hardware']['udev']: |
|
1458 |
device_path = udev_data['P'] |
|
1459 |
if device_path == UDEV_ROOT_PATH: |
|
1460 |
device = UdevDevice( |
|
1461 |
self, udev_data, sysfs_data=sysfs_data.get(device_path), |
|
1462 |
dmi_data=dmi_data) |
|
1463 |
else: |
|
1464 |
device = UdevDevice( |
|
1465 |
self, udev_data, sysfs_data=sysfs_data.get(device_path)) |
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1466 |
self.devices[device_path] = device |
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1467 |
|
1468 |
# The parent-child relations are derived from the path names of
|
|
1469 |
# the devices. If A and B are the path names of two devices,
|
|
1470 |
# the device with path name A is an ancestor of the device with
|
|
1471 |
# path name B, iff B.startswith(A). If C is the set of the path
|
|
1472 |
# names of all ancestors of A, the element with the longest path
|
|
1473 |
# name belongs to the parent of A.
|
|
1474 |
#
|
|
1475 |
# There is one exception to this rule: The root node has the
|
|
1476 |
# the path name '/devices/LNXSYSTM:00', while the path names
|
|
1477 |
# of PCI devices start with '/devices/pci'. We'll temporarily
|
|
1478 |
# change the path name of the root device so that the rule
|
|
1479 |
# holds for all devices.
|
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1480 |
if UDEV_ROOT_PATH not in self.devices: |
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1481 |
self._logError('No udev root device defined', self.submission_key) |
1482 |
return False |
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1483 |
self.devices['/devices'] = self.devices[UDEV_ROOT_PATH] |
1484 |
del self.devices[UDEV_ROOT_PATH] |
|
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1485 |
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1486 |
path_names = sorted(self.devices, key=len, reverse=True) |
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1487 |
for path_index, path_name in enumerate(path_names[:-1]): |
1488 |
# Ensure that the last ancestor of each device is our
|
|
1489 |
# root node.
|
|
1490 |
if not path_name.startswith('/devices'): |
|
1491 |
self._logError( |
|
1492 |
'Invalid device path name: %r' % path_name, |
|
1493 |
self.submission_key) |
|
1494 |
return False |
|
1495 |
for parent_path in path_names[path_index+1:]: |
|
1496 |
if path_name.startswith(parent_path): |
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1497 |
self.devices[parent_path].addChild( |
1498 |
self.devices[path_name]) |
|
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1499 |
break
|
9710.4.8
by Abel Deuring
implemented reviewer's comments |
1500 |
self.devices[UDEV_ROOT_PATH] = self.devices['/devices'] |
1501 |
del self.devices['/devices'] |
|
9710.4.4
by Abel Deuring
new method SubmissionParser.buildUdevDeviceList() |
1502 |
return True |
1503 |
||
9747.1.4
by Abel Deuring
changed SubmissionParser.getKernelPackageName into property SubmissionParser.kernel_package_name; added code to kernel_package_name to deal with data from HWDB submissions with ude data. |
1504 |
@cachedproperty
|
1505 |
def kernel_package_name(self): |
|
1506 |
"""The kernel package name for the submission."""
|
|
1507 |
if ROOT_UDI in self.devices: |
|
1508 |
root_hal_device = self.devices[ROOT_UDI] |
|
1509 |
kernel_version = root_hal_device.getProperty( |
|
1510 |
'system.kernel.version') |
|
1511 |
else: |
|
1512 |
kernel_version = self.parsed_data['summary'].get('kernel-release') |
|
6533.1.2
by Abel Deuring
implemented reviewer's comments |
1513 |
if kernel_version is None: |
6533.1.3
by Abel Deuring
implemented more reviewer comments. |
1514 |
self._logWarning( |
1515 |
'Submission does not provide property system.kernel.version '
|
|
9747.1.4
by Abel Deuring
changed SubmissionParser.getKernelPackageName into property SubmissionParser.kernel_package_name; added code to kernel_package_name to deal with data from HWDB submissions with ude data. |
1516 |
'for /org/freedesktop/Hal/devices/computer or a summary '
|
1517 |
'sub-node <kernel-release>.') |
|
6533.1.2
by Abel Deuring
implemented reviewer's comments |
1518 |
return None |
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
1519 |
kernel_package_name = 'linux-image-' + kernel_version |
6533.1.2
by Abel Deuring
implemented reviewer's comments |
1520 |
packages = self.parsed_data['software']['packages'] |
7230.3.2
by Abel Deuring
implemented reviewer's comments |
1521 |
# The submission is not required to provide any package data...
|
1522 |
if packages and kernel_package_name not in packages: |
|
1523 |
# ...but if we have it, we want it to be consistent with
|
|
1524 |
# the HAL root node property.
|
|
1525 |
self._logWarning( |
|
1526 |
'Inconsistent kernel version data: According to HAL the '
|
|
1527 |
'kernel is %s, but the submission does not know about a ' |
|
1528 |
'kernel package %s' |
|
9747.1.4
by Abel Deuring
changed SubmissionParser.getKernelPackageName into property SubmissionParser.kernel_package_name; added code to kernel_package_name to deal with data from HWDB submissions with ude data. |
1529 |
% (kernel_version, kernel_package_name)) |
7230.3.2
by Abel Deuring
implemented reviewer's comments |
1530 |
return None |
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
1531 |
return kernel_package_name |
1532 |
||
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
1533 |
def processSubmission(self, submission): |
1534 |
"""Process a submisson.
|
|
1535 |
||
1536 |
:return: True, if the submission could be sucessfully processed,
|
|
1537 |
otherwise False.
|
|
1538 |
:param submission: An IHWSubmission instance.
|
|
1539 |
"""
|
|
1540 |
raw_submission = submission.raw_submission |
|
7881.6.5
by Abel Deuring
shortened the time the HWDB processing script waits for a response from the Librarian |
1541 |
# This script runs once per day and can need a few hours to run.
|
1542 |
# Short-lived Librarian server failures or a server restart should
|
|
1543 |
# not break this script, so let's wait for 10 minutes for a
|
|
1544 |
# response from the Librarian.
|
|
1545 |
raw_submission.open(timeout=600) |
|
1546 |
submission_data = raw_submission.read(timeout=600) |
|
7881.6.4
by Abel Deuring
re-implementation of handling Librarian errors in scripts/hwdbsubmissions.py, based on better error handling in FileDownloadClient.getFileByAlias(). |
1547 |
raw_submission.close() |
1548 |
||
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
1549 |
# We assume that the data has been sent bzip2-compressed,
|
1550 |
# but this is not checked when the data is submitted.
|
|
1551 |
expanded_data = None |
|
1552 |
try: |
|
1553 |
expanded_data = bz2.decompress(submission_data) |
|
1554 |
except IOError: |
|
1555 |
# An IOError is raised, if the data is not BZip2-compressed.
|
|
1556 |
# We assume in this case that valid uncompressed data has been
|
|
1557 |
# submitted. If this assumption is wrong, parseSubmission()
|
|
1558 |
# or checkConsistency() will complain, hence we don't check
|
|
1559 |
# anything else here.
|
|
1560 |
pass
|
|
1561 |
if expanded_data is not None: |
|
1562 |
submission_data = expanded_data |
|
1563 |
||
1564 |
parsed_data = self.parseSubmission( |
|
1565 |
submission_data, submission.submission_key) |
|
1566 |
if parsed_data is None: |
|
1567 |
return False |
|
1568 |
self.parsed_data = parsed_data |
|
1569 |
if not self.checkConsistency(parsed_data): |
|
1570 |
return False |
|
9710.4.7
by Abel Deuring
renamed SubmissionParser.buildDeviceList() to buildHalDeviceList(); new method buildDeviceList(); SubmissionParser.hal_devices renamed to SubmissionParser.devices |
1571 |
if not self.buildDeviceList(parsed_data): |
1572 |
return False |
|
9747.1.11
by Abel Deuring
new property SubmissionParser.root_device; replaced access to self.udi by self.device_id in BaseDevice.is_real_device |
1573 |
self.root_device.createDBData(submission, None) |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
1574 |
return True |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1575 |
|
9747.1.11
by Abel Deuring
new property SubmissionParser.root_device; replaced access to self.udi by self.device_id in BaseDevice.is_real_device |
1576 |
@property
|
1577 |
def root_device(self): |
|
1578 |
"""The HALDevice of UdevDevice node of the root device."""
|
|
1579 |
# checkConsistency ensures that we have either a device with the
|
|
9747.1.12
by Abel Deuring
fixed a typo |
1580 |
# key ROOT_UDI or a device with the key UDEV_ROOT_PATH.
|
9747.1.11
by Abel Deuring
new property SubmissionParser.root_device; replaced access to self.udi by self.device_id in BaseDevice.is_real_device |
1581 |
if ROOT_UDI in self.devices: |
1582 |
return self.devices[ROOT_UDI] |
|
1583 |
else: |
|
1584 |
return self.devices[UDEV_ROOT_PATH] |
|
1585 |
||
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1586 |
|
1587 |
class BaseDevice: |
|
1588 |
"""A base class to represent device data from HAL and udev."""
|
|
9600.1.2
by Abel Deuring
Implemented reviewer's comments |
1589 |
|
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1590 |
def __init__(self, parser): |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1591 |
self.children = [] |
1592 |
self.parser = parser |
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1593 |
self.parent = None |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1594 |
|
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1595 |
# Translation of the HAL info.bus/info.subsystem property and the
|
1596 |
# udev property SUBSYSTEM to HWBus enumerated buses.
|
|
1597 |
subsystem_hwbus = { |
|
1598 |
'pcmcia': HWBus.PCMCIA, |
|
1599 |
'usb_device': HWBus.USB, |
|
1600 |
'ide': HWBus.IDE, |
|
1601 |
'serio': HWBus.SERIAL, |
|
1602 |
}
|
|
1603 |
||
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1604 |
def addChild(self, child): |
6261.2.2
by Abel Deuring
implemented reviewer's comments |
1605 |
"""Add a child device and set the child's parent."""
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1606 |
assert type(child) == type(self) |
1607 |
self.children.append(child) |
|
6261.2.2
by Abel Deuring
implemented reviewer's comments |
1608 |
child.parent = self |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1609 |
|
1610 |
# Translation of subclasses of the PCI class storage to HWBus
|
|
6261.2.2
by Abel Deuring
implemented reviewer's comments |
1611 |
# enumerated buses. The Linux kernel accesses IDE and SATA disks
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1612 |
# and CDROM drives via the SCSI system; we want to know the real bus
|
1613 |
# of the drive. See for example the file include/linux/pci_ids.h
|
|
1614 |
# in the Linux kernel sources for a list of PCI device classes and
|
|
1615 |
# subclasses. Note that the subclass 4 (RAID) is missing. While it
|
|
1616 |
# may make sense to declare a RAID storage class for PCI devices,
|
|
1617 |
# "RAID" does not tell us anything about the bus of the storage
|
|
1618 |
# devices.
|
|
1619 |
pci_storage_subclass_hwbus = { |
|
1620 |
0: HWBus.SCSI, |
|
1621 |
1: HWBus.IDE, |
|
1622 |
2: HWBus.FLOPPY, |
|
1623 |
3: HWBus.IPI, # Intelligent Peripheral Interface |
|
1624 |
5: HWBus.ATA, |
|
1625 |
6: HWBus.SATA, |
|
1626 |
7: HWBus.SAS, |
|
1627 |
}
|
|
1628 |
||
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1629 |
@property
|
1630 |
def device_id(self): |
|
1631 |
"""A unique ID for this device."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1632 |
raise NotImplementedError |
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1633 |
|
1634 |
@property
|
|
1635 |
def pci_class(self): |
|
1636 |
"""The PCI device class of the device or None for Non-PCI devices."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1637 |
raise NotImplementedError |
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1638 |
|
1639 |
@property
|
|
1640 |
def pci_subclass(self): |
|
1641 |
"""The PCI device sub-class of the device or None for Non-PCI devices.
|
|
1642 |
"""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1643 |
raise NotImplementedError |
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1644 |
|
9600.1.3
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 2 |
1645 |
@property
|
1646 |
def usb_vendor_id(self): |
|
1647 |
"""The USB vendor ID of the device or None for Non-USB devices."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1648 |
raise NotImplementedError |
9600.1.3
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 2 |
1649 |
|
1650 |
@property
|
|
1651 |
def usb_product_id(self): |
|
1652 |
"""The USB product ID of the device or None for Non-USB devices."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1653 |
raise NotImplementedError |
9600.1.3
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 2 |
1654 |
|
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1655 |
@property
|
1656 |
def scsi_vendor(self): |
|
1657 |
"""The SCSI vendor name of the device or None for Non-SCSI devices."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1658 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1659 |
|
1660 |
@property
|
|
1661 |
def scsi_model(self): |
|
1662 |
"""The SCSI model name of the device or None for Non-SCSI devices."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1663 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1664 |
|
1665 |
@property
|
|
1666 |
def vendor(self): |
|
1667 |
"""The vendor of this device."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1668 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1669 |
|
1670 |
@property
|
|
1671 |
def product(self): |
|
1672 |
"""The vendor of this device."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1673 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1674 |
|
1675 |
@property
|
|
1676 |
def vendor_id(self): |
|
1677 |
"""The vendor ID of this device."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1678 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1679 |
|
1680 |
@property
|
|
1681 |
def product_id(self): |
|
1682 |
"""The product ID of this device."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1683 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1684 |
|
1685 |
@property
|
|
1686 |
def vendor_id_for_db(self): |
|
1687 |
"""The vendor ID in the representation needed for the HWDB tables.
|
|
1688 |
||
1689 |
USB and PCI IDs are represented in the database in hexadecimal,
|
|
1690 |
while the IDs provided by HAL are integers.
|
|
1691 |
||
1692 |
The SCSI vendor name is right-padded with spaces to 8 bytes.
|
|
1693 |
"""
|
|
1694 |
bus = self.raw_bus |
|
1695 |
format = DB_FORMAT_FOR_VENDOR_ID.get(bus) |
|
1696 |
if format is None: |
|
1697 |
return self.vendor_id |
|
1698 |
else: |
|
1699 |
return format % self.vendor_id |
|
1700 |
||
1701 |
@property
|
|
1702 |
def product_id_for_db(self): |
|
1703 |
"""The product ID in the representation needed for the HWDB tables.
|
|
1704 |
||
1705 |
USB and PCI IDs are represented in the database in hexadecimal,
|
|
1706 |
while the IDs provided by HAL are integers.
|
|
1707 |
||
1708 |
The SCSI product name is right-padded with spaces to 16 bytes.
|
|
1709 |
"""
|
|
1710 |
bus = self.raw_bus |
|
1711 |
format = DB_FORMAT_FOR_PRODUCT_ID.get(bus) |
|
1712 |
if format is None: |
|
1713 |
return self.product_id |
|
1714 |
else: |
|
1715 |
return format % self.product_id |
|
1716 |
||
1717 |
@property
|
|
1718 |
def driver_name(self): |
|
1719 |
"""The name of the driver contolling this device. May be None."""
|
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
1720 |
raise NotImplementedError |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
1721 |
|
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
1722 |
@property
|
1723 |
def scsi_controller(self): |
|
1724 |
"""Return the SCSI host controller for this device."""
|
|
1725 |
raise NotImplementedError |
|
1726 |
||
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1727 |
def translateScsiBus(self): |
7178.2.1
by Abel Deuring
improved detection of the device bus in class HALDevice |
1728 |
"""Return the real bus of a device where raw_bus=='scsi'.
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1729 |
|
1730 |
The kernel uses the SCSI layer to access storage devices
|
|
1731 |
connected via the USB, IDE, SATA buses. See `is_real_device`
|
|
1732 |
for more details. This method determines the real bus
|
|
1733 |
of a device accessed via the kernel's SCSI subsystem.
|
|
1734 |
"""
|
|
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
1735 |
scsi_controller = self.scsi_controller |
1736 |
if scsi_controller is None: |
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1737 |
return None |
1738 |
||
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
1739 |
scsi_controller_bus = scsi_controller.raw_bus |
1740 |
if scsi_controller_bus == 'pci': |
|
1741 |
if (scsi_controller.pci_class != PCI_CLASS_STORAGE): |
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1742 |
# This is not a storage class PCI device? This
|
1743 |
# indicates a bug somewhere in HAL or in the hwdb
|
|
1744 |
# client, or a fake submission.
|
|
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
1745 |
device_class = scsi_controller.pci_class |
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
1746 |
self.parser._logWarning( |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1747 |
'A (possibly fake) SCSI device %s is connected to ' |
1748 |
'PCI device %s that has the PCI device class %s; ' |
|
6533.1.2
by Abel Deuring
implemented reviewer's comments |
1749 |
'expected class 1 (storage).'
|
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
1750 |
% (self.device_id, scsi_controller.device_id, |
1751 |
device_class)) |
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1752 |
return None |
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
1753 |
pci_subclass = scsi_controller.pci_subclass |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1754 |
return self.pci_storage_subclass_hwbus.get(pci_subclass) |
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
1755 |
elif scsi_controller_bus in ('usb', 'usb_interface'): |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1756 |
# USB storage devices have the following HAL device hierarchy:
|
1757 |
# - HAL node for the USB device. info.bus == 'usb_device',
|
|
1758 |
# device class == 0, device subclass == 0
|
|
1759 |
# - HAL node for the USB storage interface. info.bus == 'usb',
|
|
1760 |
# interface class 8, interface subclass 6
|
|
1761 |
# (see http://www.usb.org/developers/devclass_docs
|
|
1762 |
# /usb_msc_overview_1.2.pdf)
|
|
7178.2.1
by Abel Deuring
improved detection of the device bus in class HALDevice |
1763 |
# - HAL node for the (fake) SCSI host. raw_bus is None
|
1764 |
# - HAL node for the (fake) SCSI device. raw_bus == 'scsi'
|
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1765 |
# - HAL node for the mass storage device
|
1766 |
#
|
|
1767 |
# Physically, the storage device can be:
|
|
1768 |
# (1) a genuine USB device, like a memory stick
|
|
1769 |
# (2) a IDE/SATA hard disk, connected to a USB -> SATA/IDE
|
|
1770 |
# bridge
|
|
1771 |
# (3) a card reader
|
|
1772 |
# There is no formal way to distinguish cases (1) and (2):
|
|
1773 |
# The device and interface classes are in both cases
|
|
1774 |
# identical; the only way to figure out, if we have a USB
|
|
1775 |
# hard disk enclosure or a USB memory stick would be to
|
|
1776 |
# look at the vendor or product names, or to look up some
|
|
1777 |
# external data sources. Of course, we can also ask the
|
|
1778 |
# submitter in the future.
|
|
1779 |
#
|
|
1780 |
# The cases (1) and (2) differ from (3) in the property
|
|
1781 |
# the property storage.removable. For (1) and (2), this
|
|
1782 |
# property is False, for (3) it is True. Since we do not
|
|
1783 |
# store at present any device characteristics in the HWDB,
|
|
1784 |
# so there is no point to distinguish between (1), (2) on
|
|
1785 |
# one side and (3) on the other side. Distinguishing
|
|
1786 |
# between (1) and (2) might be more interesting, because
|
|
1787 |
# a hard disk is clearly a separate device, but as written,
|
|
1788 |
# it is hard to distinguish between (1) and (2)
|
|
1789 |
#
|
|
1790 |
# To sum up: we cannot get any interesting and reliable
|
|
1791 |
# information about the details of USB storage device,
|
|
1792 |
# so we'll treat those devices as "black boxes".
|
|
1793 |
return None |
|
1794 |
else: |
|
1795 |
return HWBus.SCSI |
|
6261.2.5
by Abel Deuring
implemented reviewer's commets |
1796 |
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1797 |
def translatePciBus(self): |
1798 |
# Cardbus (aka PCCard, sometimes also incorrectly called
|
|
1799 |
# PCMCIA) devices are treated as PCI devices by the kernel.
|
|
1800 |
# We can detect PCCards by checking that the parent device
|
|
1801 |
# is a PCI bridge (device class 6) for the Cardbus (device
|
|
1802 |
# subclass 7).
|
|
1803 |
# XXX Abel Deuring 2005-05-14 How can we detect ExpressCards?
|
|
1804 |
# I do not have any such card at present...
|
|
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1805 |
parent_class = self.parent.pci_class |
1806 |
parent_subclass = self.parent.pci_subclass |
|
6261.2.6
by Abel Deuring
implemented reviewer's comments |
1807 |
if (parent_class == PCI_CLASS_BRIDGE |
1808 |
and parent_subclass == PCI_SUBCLASS_BRIDGE_CARDBUS): |
|
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1809 |
return HWBus.PCCARD |
1810 |
else: |
|
1811 |
return HWBus.PCI |
|
1812 |
||
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1813 |
@property
|
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
1814 |
def is_root_device(self): |
1815 |
"""Return True is this is the root node of all devicese, else False.
|
|
1816 |
"""
|
|
1817 |
raise NotImplementedError |
|
1818 |
||
1819 |
@property
|
|
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1820 |
def raw_bus(self): |
1821 |
"""Return the device bus as specified by HAL or udev."""
|
|
9600.1.6
by Abel Deuring
removed () from NotImplementedError() |
1822 |
raise NotImplementedError |
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1823 |
|
7178.2.2
by Abel Deuring
changed method HALDevice.getRealBus() into property HALDevice.real_bus; fixed a typo |
1824 |
@property
|
1825 |
def real_bus(self): |
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1826 |
"""Return the bus this device connects to on the host side.
|
1827 |
||
1828 |
:return: A bus as enumerated in HWBus or None, if the bus
|
|
1829 |
cannot be determined.
|
|
1830 |
"""
|
|
7178.2.1
by Abel Deuring
improved detection of the device bus in class HALDevice |
1831 |
device_bus = self.raw_bus |
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
1832 |
result = self.subsystem_hwbus.get(device_bus) |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1833 |
if result is not None: |
1834 |
return result |
|
1835 |
||
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
1836 |
if device_bus in ('scsi', 'scsi_device'): |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1837 |
return self.translateScsiBus() |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1838 |
elif device_bus == 'pci': |
6261.2.3
by Abel Deuring
implemented reviewer's comments |
1839 |
return self.translatePciBus() |
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
1840 |
elif self.is_root_device: |
6533.1.2
by Abel Deuring
implemented reviewer's comments |
1841 |
# The computer itself. In Hardy, HAL provides no info.bus
|
1842 |
# for the machine itself; older versions set info.bus to
|
|
1843 |
# 'unknown', hence it is better to use the machine's
|
|
1844 |
# UDI.
|
|
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1845 |
return HWBus.SYSTEM |
1846 |
else: |
|
1847 |
self.parser._logWarning( |
|
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
1848 |
'Unknown bus %r for device %s' % (device_bus, self.device_id)) |
6261.2.1
by Abel Deuring
Implementation of class HALDevice, part 1 |
1849 |
return None |
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
1850 |
|
1851 |
@property
|
|
1852 |
def is_real_device(self): |
|
1853 |
"""True, if the HAL device correspends to a real device.
|
|
1854 |
||
1855 |
In many cases HAL has more than one device entry for the
|
|
1856 |
same physical device. We are only interested in real, physical,
|
|
1857 |
devices but not in the fine details, how HAL represents different
|
|
1858 |
aspects of them.
|
|
1859 |
||
1860 |
For example, the HAL device node hiearchy for a SATA disk and
|
|
6261.2.5
by Abel Deuring
implemented reviewer's commets |
1861 |
its host controller looks like this:
|
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
1862 |
|
1863 |
HAL device node of the host controller
|
|
1864 |
udi: .../pci_8086_27c5
|
|
1865 |
HAL properties:
|
|
1866 |
info.bus: pci
|
|
1867 |
pci.device_class: 1 (storage)
|
|
1868 |
pci.device_subclass: 6 (SATA)
|
|
1869 |
info.linux.driver: ahci
|
|
1870 |
||
1871 |
HAL device node of the "output aspect" of the host controller
|
|
1872 |
udi: .../pci_8086_27c5_scsi_host
|
|
1873 |
HAL properties:
|
|
1874 |
info.bus: n/a
|
|
1875 |
info.driver: n/a
|
|
1876 |
info.parent: .../pci_8086_27c5
|
|
1877 |
||
1878 |
HAL device node of a hard disk.
|
|
1879 |
udi: .../pci_8086_27c5_scsi_host_scsi_device_lun0
|
|
1880 |
HAL properties:
|
|
1881 |
info.bus: scsi
|
|
1882 |
info.driver: sd
|
|
1883 |
info.parent: .../pci_8086_27c5_scsi_host
|
|
1884 |
||
1885 |
HAL device node of the "storage aspect" of the hard disk
|
|
1886 |
udi: .../storage_serial_1ATA_Hitachi_HTS541616J9SA00_SB...
|
|
1887 |
HAL properties
|
|
1888 |
info.driver: n/a
|
|
1889 |
info.parent: .../pci_8086_27c5_scsi_host_scsi_device_lun0
|
|
1890 |
||
1891 |
HAL device node of a disk partition:
|
|
1892 |
udi: .../volume_uuid_0ee803cf_...
|
|
1893 |
HAL properties
|
|
1894 |
info.driver: n/a
|
|
1895 |
info.parent: .../storage_serial_1ATA_Hitachi_HTS541616J...
|
|
1896 |
||
1897 |
(optionally more nodes for more partitions)
|
|
1898 |
||
1899 |
HAL device node of the "generic SCSI aspect" of the hard disk:
|
|
1900 |
udi: .../pci_8086_27c5_scsi_host_scsi_device_lun0_scsi_generic
|
|
1901 |
info.driver: n/a
|
|
1902 |
info.parent: .../pci_8086_27c5_scsi_host_scsi_device_lun0
|
|
1903 |
||
1904 |
This disk is _not_ a SCSI disk, but a SATA disk. In other words,
|
|
1905 |
the SCSI details are in this case just an artifact of the Linux
|
|
1906 |
kernel, which uses its SCSI subsystem as a "central hub" to access
|
|
1907 |
IDE, SATA, USB, IEEE1394 storage devices. The only interesting
|
|
1908 |
detail for us is that the sd driver is involved in accesses to the
|
|
1909 |
disk.
|
|
1910 |
||
1911 |
Heuristics:
|
|
1912 |
||
1913 |
- Most real devices have the property info.bus; we consider only
|
|
1914 |
those devices to be real which have this property set.
|
|
1915 |
||
1916 |
- As written above, the SCSI bus often appears as an artifact;
|
|
1917 |
for PCI host controllers, their properties pci.device_class
|
|
6261.2.5
by Abel Deuring
implemented reviewer's commets |
1918 |
and pci.device_subclass tell us if we have a real SCSI host
|
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
1919 |
controller: pci.device_class == 1 means a storage controller,
|
1920 |
pci.device_subclass == 0 means a SCSI controller. This works
|
|
1921 |
too for PCCard controllers, which use the PCI device class
|
|
1922 |
numbers too.
|
|
1923 |
||
1924 |
- The value "usb_device" of the HAL property info.bus identifies
|
|
1925 |
USB devices, with one exception: The USB host controller, which
|
|
1926 |
itself has an info.bus property with the value "pci", has a
|
|
1927 |
sub-device with info.bus='usb_device' for its "output aspect".
|
|
1928 |
These sub-devices can be identified by the device class their
|
|
1929 |
parent and by their USB vendor/product IDs, which are 0:0.
|
|
7598.1.2
by Abel Deuring
implemented reviewer's comments |
1930 |
|
1931 |
Several info.bus/info.subsystem values always relate to HAL nodes
|
|
1932 |
which describe only "aspects" of physical devcies which are
|
|
1933 |
represented by other HAL nodes:
|
|
1934 |
||
1935 |
- bus is None for a number of "virtual components", like
|
|
1936 |
/org/freedesktop/Hal/devices/computer_alsa_timer or
|
|
1937 |
/org/freedesktop/Hal/devices/computer_oss_sequencer, so
|
|
1938 |
we ignore them. (The real sound devices appear with
|
|
1939 |
other UDIs in HAL.)
|
|
1940 |
||
1941 |
XXX Abel Deuring 20080425: This ignores a few components
|
|
1942 |
like laptop batteries or the CPU, where info.bus is None.
|
|
1943 |
Since these components are not the most important ones
|
|
1944 |
for the HWDB, we'll ignore them for now. Bug 237038.
|
|
1945 |
||
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
1946 |
- 'disk' is used udev submissions for a node related to the
|
1947 |
sd or sr driver of (real or fake) SCSI block devices.
|
|
1948 |
||
7658.2.1
by Abel Deuring
Extended the list of device buses that should be ignored during HWDB submission processing. |
1949 |
- info.bus == 'drm' is used by the HAL for the direct
|
1950 |
rendering interface of a graphics card.
|
|
1951 |
||
1952 |
- info.bus == 'dvb' is used by HAL for the "input aspect"
|
|
1953 |
of DVB receivers
|
|
1954 |
||
1955 |
- info.bus == 'memstick_host' is used by HAL for the "output aspect"
|
|
1956 |
of memory sticks.
|
|
1957 |
||
7598.1.2
by Abel Deuring
implemented reviewer's comments |
1958 |
- info.bus == 'net' is used by the HAL version in
|
1959 |
Intrepid for the "output aspects" of network devices.
|
|
1960 |
||
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
1961 |
- 'partition' is used in udev submissions for a node
|
1962 |
related to disk partition
|
|
1963 |
||
1964 |
- 'scsi_disk' is used in udev submissions for a sub-node of
|
|
1965 |
the real device node.
|
|
1966 |
||
7598.1.2
by Abel Deuring
implemented reviewer's comments |
1967 |
info.bus == 'scsi_generic' is used by the HAL version in
|
1968 |
Intrepid for a HAL node representing the generic
|
|
1969 |
interface of a SCSI device.
|
|
1970 |
||
1971 |
info.bus == 'scsi_host' is used by the HAL version in
|
|
1972 |
Intrepid for real and "fake" SCSI host controllers.
|
|
1973 |
(On Hardy, these nodes have no info.bus property.)
|
|
1974 |
HAL nodes with this bus value are sub-nodes for the
|
|
1975 |
"SCSI aspect" of another HAL node which represents the
|
|
1976 |
real device.
|
|
1977 |
||
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
1978 |
'scsi_target' is used in udev data for SCSI target nodes,
|
1979 |
the parent of a SCSI device (or LUN) node.
|
|
1980 |
||
1981 |
'spi_transport' (SCSI Parallel Transport) is used in
|
|
1982 |
udev data for a sub-node of real SCSI devices.
|
|
1983 |
||
7598.1.2
by Abel Deuring
implemented reviewer's comments |
1984 |
info.bus == 'sound' is used by the HAL version in
|
1985 |
Intrepid for "aspects" of sound devices.
|
|
1986 |
||
1987 |
info.bus == 'ssb' is used for "aspects" of Broadcom
|
|
1988 |
Ethernet and WLAN devices, but like 'usb', they do not
|
|
1989 |
represent separate devices.
|
|
1990 |
||
7658.2.1
by Abel Deuring
Extended the list of device buses that should be ignored during HWDB submission processing. |
1991 |
info.bus == 'tty' is used for the "output aspect"
|
1992 |
of serial output devices (RS232, modems etc). It appears
|
|
1993 |
for USB and PCI devices as well as for legacy devices
|
|
1994 |
like the 8250/16450/16550 controllers.
|
|
1995 |
||
7598.1.2
by Abel Deuring
implemented reviewer's comments |
1996 |
info.bus == 'usb' is used for end points of USB devices;
|
1997 |
the root node of a USB device has info.bus == 'usb_device'.
|
|
7658.2.1
by Abel Deuring
Extended the list of device buses that should be ignored during HWDB submission processing. |
1998 |
|
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
1999 |
'usb_interface' is used in udv submissions for interface
|
2000 |
nodes of USB devices.
|
|
2001 |
||
9600.1.3
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 2 |
2002 |
info.bus == 'video4linux' is used for the "input aspect"
|
7658.2.1
by Abel Deuring
Extended the list of device buses that should be ignored during HWDB submission processing. |
2003 |
of video devices.
|
9747.1.10
by Abel Deuring
Added a number of buses that should treated as being 'unreal' or 'unprocessible' to BaseDevice.is_real_device and BaseDevice.has_reliable_data. |
2004 |
|
2005 |
'ac97' is used in submissions with udev data for a sub-node
|
|
2006 |
of sound devices.
|
|
2007 |
||
2008 |
'hid' is used in submissions with udev data for a sub-node
|
|
2009 |
of USB input devices.
|
|
2010 |
||
2011 |
'drm_minor', 'pci_express', 'tifm_adapter', 'gameport',
|
|
2012 |
'spi_host', 'tifm', 'wlan' are used in submissions with
|
|
2013 |
udev data for sub-nodes of PCI devices.
|
|
2014 |
||
2015 |
'pcmcia_socket' is used in submissions with udev data for
|
|
2016 |
a sub-node of PC Card and PCMCIA bridges.
|
|
2017 |
||
2018 |
'ieee80211' is used in submissions with udev data for
|
|
2019 |
sub-nodes IEEE 802.11 WLAN devices.
|
|
2020 |
||
2021 |
'host', 'link' are used in submissions with udev data for
|
|
2022 |
sub.nodes of bluetooth devices.
|
|
2023 |
||
2024 |
'usb_host' and 'usbmon' are used in submissions with udev
|
|
2025 |
data for sub-nodes of USB controllers.
|
|
2026 |
||
2027 |
'usb_endpoint', 'usb-serial', 'lirc' are used in
|
|
2028 |
submissions with udev data for sub-nodes of USB devices.
|
|
2029 |
||
2030 |
'enclosure' is used in submissions with udev data for a
|
|
2031 |
sub.node of SCSI devices.
|
|
2032 |
||
2033 |
'graphics' is used in submissions with udev data for a
|
|
2034 |
sub-node of graphics cards.
|
|
2035 |
||
2036 |
'hwmon' is is used in submissions with udev data in
|
|
2037 |
many sub-nodes.
|
|
9830.7.1
by Abel Deuring
hwdbsubmissions.py: Extended the sets of bus names known to belong to virtual devices or used for nodes that describe only aspects of real devices |
2038 |
|
2039 |
'sas_phy', 'sas_device', 'sas_end_device', 'sas_port',
|
|
2040 |
'sas_host' is used in submissions with udev data for
|
|
2041 |
details of SAS controllers.
|
|
2042 |
||
2043 |
'mISDN' is used in submissions with udev data for the
|
|
2044 |
I/O aspects of ISDN adapters.
|
|
2045 |
||
2046 |
'pvrusb2' is used in submissions with udev data for the
|
|
2047 |
input aspect of some DVB adapters.
|
|
2048 |
||
2049 |
'memstick' is used in submissions with udev data for the
|
|
2050 |
I/O aspect of memory stick controllers.
|
|
2051 |
||
2052 |
'bttv-sub' is used in submissions with udev data for the
|
|
2053 |
I/O aspects of some TV receivers.
|
|
2054 |
||
2055 |
'scsi_tape' is used in submissions with udev data for
|
|
2056 |
details of SCSI tape drives.
|
|
2057 |
"""
|
|
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
2058 |
# The root node is always a real device, but its raw_bus
|
2059 |
# property can have different values: None or 'Unknown' in
|
|
2060 |
# submissions with HAL data, 'acpi' for submissions with udev
|
|
2061 |
# data.
|
|
2062 |
if self.is_root_device: |
|
2063 |
return True |
|
2064 |
||
7465.6.1
by Abel Deuring
fix for bug 308510: Many devices ignored during submission processing when the bus is given in property info.subsystem, not info.bus |
2065 |
bus = self.raw_bus |
7658.2.2
by Abel Deuring
implemented reviewer's comments |
2066 |
# This set of buses is only used once; it's easier to have it
|
2067 |
# here than to put it elsewhere and have to document its
|
|
2068 |
# location and purpose.
|
|
9830.7.1
by Abel Deuring
hwdbsubmissions.py: Extended the sets of bus names known to belong to virtual devices or used for nodes that describe only aspects of real devices |
2069 |
if bus in (None, 'ac97', 'bttv-sub', 'disk', 'drm', 'drm_minor', |
2070 |
'dvb', 'enclosure', 'gameport', 'graphics', 'hid', 'host', |
|
2071 |
'hwmon', 'ieee80211', 'link', 'lirc', 'mISDN', 'memstick', |
|
2072 |
'memstick_host', 'net', 'partition', 'pci_express', |
|
2073 |
'pcmcia_socket', 'pvrusb2', 'sas_device', 'sas_end_device', |
|
2074 |
'sas_host', 'sas_phy', 'sas_port', 'scsi_disk', |
|
2075 |
'scsi_generic', 'scsi_host', 'scsi_tape', 'scsi_target', |
|
9747.1.10
by Abel Deuring
Added a number of buses that should treated as being 'unreal' or 'unprocessible' to BaseDevice.is_real_device and BaseDevice.has_reliable_data. |
2076 |
'sound', 'spi_host', 'spi_transport', 'ssb', 'tifm', |
2077 |
'tifm_adapter', 'tty', 'usb', 'usb-serial', 'usb_endpoint', |
|
2078 |
'usb_host', 'usb_interface', 'usbmon', 'video4linux', |
|
2079 |
'wlan'): |
|
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
2080 |
return False |
6261.2.5
by Abel Deuring
implemented reviewer's commets |
2081 |
elif bus == 'usb_device': |
9600.1.3
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 2 |
2082 |
vendor_id = self.usb_vendor_id |
2083 |
product_id = self.usb_product_id |
|
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2084 |
if vendor_id == 0 and product_id == 0: |
2085 |
# double-check: The parent device should be a PCI host
|
|
2086 |
# controller, identifiable by its device class and subclass.
|
|
6912.5.21
by Curtis Hovey
Updated the XXX comment's metadata using the bug found in the comment text. |
2087 |
# XXX Abel Deuring 2008-04-28 Bug=237039: This ignores other
|
2088 |
# possible bridges, like ISA->USB..
|
|
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2089 |
parent = self.parent |
7178.2.1
by Abel Deuring
improved detection of the device bus in class HALDevice |
2090 |
parent_bus = parent.raw_bus |
9600.1.1
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 1 |
2091 |
parent_class = parent.pci_class |
2092 |
parent_subclass = parent.pci_subclass |
|
6261.2.5
by Abel Deuring
implemented reviewer's commets |
2093 |
if (parent_bus == 'pci' |
2094 |
and parent_class == PCI_CLASS_SERIALBUS_CONTROLLER |
|
6261.2.6
by Abel Deuring
implemented reviewer's comments |
2095 |
and parent_subclass == PCI_SUBCLASS_SERIALBUS_USB): |
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2096 |
return False |
2097 |
else: |
|
2098 |
self.parser._logWarning( |
|
2099 |
'USB device found with vendor ID==0, product ID==0, '
|
|
2100 |
'where the parent device does not look like a USB '
|
|
9747.1.11
by Abel Deuring
new property SubmissionParser.root_device; replaced access to self.udi by self.device_id in BaseDevice.is_real_device |
2101 |
'host controller: %s' % self.device_id) |
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2102 |
return False |
2103 |
return True |
|
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
2104 |
elif bus in ('scsi', 'scsi_device'): |
7178.2.2
by Abel Deuring
changed method HALDevice.getRealBus() into property HALDevice.real_bus; fixed a typo |
2105 |
# Ensure consistency with HALDevice.real_bus
|
2106 |
return self.real_bus is not None |
|
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2107 |
else: |
2108 |
return True |
|
2109 |
||
2110 |
def getRealChildren(self): |
|
2111 |
"""Return the list of real child devices of this devices.
|
|
2112 |
||
2113 |
The list of real child devices consists of the direct child
|
|
2114 |
devices of this device where child.is_real_device == True, and
|
|
2115 |
of the (recursively collected) list of real sub-devices of
|
|
6261.2.5
by Abel Deuring
implemented reviewer's commets |
2116 |
those child devices where child.is_real_device == False.
|
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2117 |
"""
|
2118 |
result = [] |
|
2119 |
for sub_device in self.children: |
|
2120 |
if sub_device.is_real_device: |
|
2121 |
# XXX Abel Deuring 2008-05-06: IEEE1394 devices are a bit
|
|
2122 |
# nasty: The standard does not define any specification
|
|
2123 |
# for product IDs or product names, hence HAL often
|
|
2124 |
# uses the value 0 for the property ieee1394.product_id
|
|
2125 |
# and a value like "Unknown (0x00d04b)" for
|
|
2126 |
# ieee.product, where 0x00d04b is the vendor ID. I have
|
|
2127 |
# currently no idea how to find or generate something
|
|
2128 |
# that could be used as the product ID, so IEEE1394
|
|
2129 |
# devices are at present simply dropped from the list of
|
|
2130 |
# devices. Otherwise, we'd pollute the HWDB with
|
|
6261.2.5
by Abel Deuring
implemented reviewer's commets |
2131 |
# unreliable data. Bug 237044.
|
7178.2.1
by Abel Deuring
improved detection of the device bus in class HALDevice |
2132 |
if sub_device.raw_bus != 'ieee1394': |
6261.2.4
by Abel Deuring
Implementation of class HALDevice, part 2 |
2133 |
result.append(sub_device) |
2134 |
else: |
|
2135 |
result.extend(sub_device.getRealChildren()) |
|
2136 |
return result |
|
6261.2.8
by Abel Deuring
part 3 Implementation of class HALDevice, part 3: retrieval of vendor/product name and ID |
2137 |
|
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2138 |
@property
|
6533.1.2
by Abel Deuring
implemented reviewer's comments |
2139 |
def has_reliable_data(self): |
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2140 |
"""Can this device be stored in the HWDB?
|
2141 |
||
2142 |
Devices are identifed by (bus, vendor_id, product_id).
|
|
2143 |
At present we cannot generate reliable vendor and/or product
|
|
7598.1.1
by Abel Deuring
several HAL bus/subsystem names added to the the set of ignored names |
2144 |
IDs for devices with the following values of the HAL
|
2145 |
property info.bus resp. info.subsystem.
|
|
2146 |
||
2147 |
info.bus == 'backlight' is used by the HAL version in
|
|
2148 |
Intrepid for the LC display. Useful vendor and product names
|
|
2149 |
are not available.
|
|
2150 |
||
7658.2.1
by Abel Deuring
Extended the list of device buses that should be ignored during HWDB submission processing. |
2151 |
info.bus == 'bluetooth': HAL does not provide any vendor/product
|
2152 |
ID data, so we can't store these devices in HWDevice.
|
|
2153 |
||
7598.1.1
by Abel Deuring
several HAL bus/subsystem names added to the the set of ignored names |
2154 |
info.bus == 'input' is used by the HAL version in
|
2155 |
Intrepid for quite different devices like keyboards, mice,
|
|
2156 |
special laptop switches and buttons, sometimes with odd
|
|
2157 |
product names like "Video Bus".
|
|
2158 |
||
2159 |
info.bus == 'misc' and info.bus == 'unknown' are obviously
|
|
2160 |
not very useful, except for the computer itself, which has
|
|
2161 |
the bus 'unknown'.
|
|
2162 |
||
2163 |
info.bus in ('mmc', 'mmc_host') is used for SD/MMC cards resp.
|
|
2164 |
the "output aspect" of card readers. We do not not have at
|
|
2165 |
present enough background information to properly extract a
|
|
2166 |
vendor and product ID from these cards.
|
|
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2167 |
|
2168 |
info.bus == 'platform' is used for devices like the i8042
|
|
2169 |
which controls keyboard and mouse; HAL has no vendor
|
|
2170 |
information for these devices, so there is no point to
|
|
2171 |
treat them as real devices.
|
|
2172 |
||
2173 |
info.bus == 'pnp' is used for components like the ancient
|
|
2174 |
AT DMA controller or the keyboard. Like for the bus
|
|
2175 |
'platform', HAL does not provide any vendor data.
|
|
2176 |
||
7598.1.1
by Abel Deuring
several HAL bus/subsystem names added to the the set of ignored names |
2177 |
info.bus == 'power_supply' is used by the HAL version in
|
2178 |
Intrepid for AC adapters an laptop batteries. We don't have
|
|
2179 |
at present enough information about possible problems with
|
|
2180 |
missing vendor/product information in order to store the
|
|
2181 |
data reliably in the HWDB.
|
|
7250.1.1
by Abel Deuring
ignore HAL devives with buses 'misc' and 'unkown' in HWDB processing |
2182 |
|
9710.4.3
by Abel Deuring
BaseDevice.has_reliable_data modified for UdevDevice; tests for Udevdevice.has_reliable_data |
2183 |
raw_bus == 'acpi' is used in udev data for the main system,
|
2184 |
for CPUs, power supply etc. Except for the main sytsem, none
|
|
2185 |
of them provides a vendor or product id, so we ignore them.
|
|
2186 |
||
9747.1.10
by Abel Deuring
Added a number of buses that should treated as being 'unreal' or 'unprocessible' to BaseDevice.is_real_device and BaseDevice.has_reliable_data. |
2187 |
raw_bus == 'video_output', 'thermal', 'vtconsole', 'bdi',
|
2188 |
'mem', 'ppp', 'vc', 'dmi', 'hidraw', 'hwmon', 'heci', 'rfkill',
|
|
9830.7.1
by Abel Deuring
hwdbsubmissions.py: Extended the sets of bus names known to belong to virtual devices or used for nodes that describe only aspects of real devices |
2189 |
'i2c-adapter', 'ttm', 'ppdev', 'printer', 'cardman_4040', 'msr',
|
2190 |
'ieee1394_protocol', 'dahdi', 'atm', 'asus_oled', 'pktcdvd' is
|
|
2191 |
used in submissions with udev data for virtual devices.
|
|
9747.1.10
by Abel Deuring
Added a number of buses that should treated as being 'unreal' or 'unprocessible' to BaseDevice.is_real_device and BaseDevice.has_reliable_data. |
2192 |
|
2193 |
'pci_bus' is used in submissions with udev data for a node
|
|
2194 |
describing a PCI bus.
|
|
2195 |
||
2196 |
'leds' is used in submissions with udev data to describe LEDs.
|
|
2197 |
||
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2198 |
XXX Abel Deuring 2008-05-06: IEEE1394 devices are a bit
|
2199 |
nasty: The standard does not define any specification
|
|
2200 |
for product IDs or product names, hence HAL often uses
|
|
2201 |
the value 0 for the property ieee1394.product_id and a
|
|
2202 |
value like "Unknown (0x00d04b)" for ieee.product, where
|
|
2203 |
0x00d04b is the vendor ID. I have currently no idea how
|
|
2204 |
to find or generate something that could be used as the
|
|
2205 |
product ID, so IEEE1394 devices are at present simply
|
|
2206 |
not stored in the HWDB. Otherwise, we'd pollute the HWDB
|
|
6533.1.2
by Abel Deuring
implemented reviewer's comments |
2207 |
with unreliable data. Bug #237044.
|
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2208 |
|
2209 |
While PCMCIA devices have a manufacturer ID, at least its
|
|
2210 |
value as provided by HAL in pcmcia.manf_id it is not very
|
|
2211 |
reliable. The HAL property pcmcia.prod_id1 is too not
|
|
2212 |
reliable. Sometimes it contains a useful vendor name like
|
|
2213 |
"O2Micro" or "ATMEL", but sometimes useless values like
|
|
2214 |
"IEEE 802.11b". See for example
|
|
2215 |
drivers/net/wireless/atmel_cs.c in the Linux kernel sources.
|
|
7233.1.1
by Abel Deuring
Processing HWDB submissions containing IDE devices without vendor and product ID causes no longer log messages about missing vendor/product ID |
2216 |
|
2217 |
Provided that a device is not excluded by the above criteria,
|
|
2218 |
ensure that we have vendor ID, product ID and product name.
|
|
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2219 |
"""
|
7250.1.1
by Abel Deuring
ignore HAL devives with buses 'misc' and 'unkown' in HWDB processing |
2220 |
bus = self.raw_bus |
9710.4.3
by Abel Deuring
BaseDevice.has_reliable_data modified for UdevDevice; tests for Udevdevice.has_reliable_data |
2221 |
if bus in ('unknown', 'acpi') and not self.is_root_device: |
7250.1.1
by Abel Deuring
ignore HAL devives with buses 'misc' and 'unkown' in HWDB processing |
2222 |
# The root node is course a real device; storing data
|
2223 |
# about other devices with the bus "unkown" is pointless.
|
|
2224 |
return False |
|
9830.7.1
by Abel Deuring
hwdbsubmissions.py: Extended the sets of bus names known to belong to virtual devices or used for nodes that describe only aspects of real devices |
2225 |
if bus in ('asus_oled', 'atm', 'backlight', 'bdi', 'bluetooth', |
2226 |
'cardman_4040', 'dahdi', 'dmi', 'heci', 'hidraw', 'hwmon', |
|
2227 |
'i2c-adapter', 'ieee1394', 'ieee1394_protocol', 'input', |
|
2228 |
'leds', 'mem', 'misc', 'mmc', 'mmc_host', 'msr', 'pci_bus', |
|
2229 |
'pcmcia', 'pktcdvd', 'platform', 'pnp', 'power_supply', |
|
2230 |
'ppdev', 'ppp', 'printer', 'rfkill', 'thermal', 'ttm', |
|
2231 |
'vc', 'video_output', 'vtconsole'): |
|
7233.1.1
by Abel Deuring
Processing HWDB submissions containing IDE devices without vendor and product ID causes no longer log messages about missing vendor/product ID |
2232 |
return False |
2233 |
||
2234 |
# We identify devices by bus, vendor ID and product ID;
|
|
2235 |
# additionally, we need a product name. If any of these
|
|
2236 |
# are not available, we can't store information for this
|
|
2237 |
# device.
|
|
2238 |
if (self.real_bus is None or self.vendor_id is None |
|
2239 |
or self.product_id is None or self.product is None): |
|
2240 |
# Many IDE devices don't provide useful vendor and product
|
|
2241 |
# data. We don't want to clutter the log with warnings
|
|
2242 |
# about this problem -- there is nothing we can do to fix
|
|
2243 |
# it.
|
|
2244 |
if self.real_bus != HWBus.IDE: |
|
2245 |
self.parser._logWarning( |
|
9710.4.3
by Abel Deuring
BaseDevice.has_reliable_data modified for UdevDevice; tests for Udevdevice.has_reliable_data |
2246 |
'A %s that is supposed to be a real device does ' |
7233.1.1
by Abel Deuring
Processing HWDB submissions containing IDE devices without vendor and product ID causes no longer log messages about missing vendor/product ID |
2247 |
'not provide bus, vendor ID, product ID or product name: '
|
2248 |
'%r %r %r %r %s' |
|
9710.4.3
by Abel Deuring
BaseDevice.has_reliable_data modified for UdevDevice; tests for Udevdevice.has_reliable_data |
2249 |
% (self.__class__.__name__, self.real_bus, self.vendor_id, |
2250 |
self.product_id, self.product, self.device_id), |
|
7233.1.1
by Abel Deuring
Processing HWDB submissions containing IDE devices without vendor and product ID causes no longer log messages about missing vendor/product ID |
2251 |
self.parser.submission_key) |
2252 |
return False |
|
2253 |
return True |
|
6533.1.1
by Abel Deuring
Implementation of class HALDevice, part 4: moved detection of devices that can't yet be processed from is_real_device into a separate property; added properties for vendor/product ID as needed for HWVendorID/HWDevice; fixed a few bugs in _logWarning calls |
2254 |
|
7242.2.1
by Abel Deuring
avoid exception when an HWDB submission with an ATA disk with a long product name is processed |
2255 |
def getScsiVendorAndModelName(self): |
7242.2.2
by Abel Deuring
implemented reviewer's comments |
2256 |
"""Separate vendor and model name of SCSI decvices.
|
7242.2.1
by Abel Deuring
avoid exception when an HWDB submission with an ATA disk with a long product name is processed |
2257 |
|
2258 |
SCSI devcies are identified by an 8 charcter vendor name
|
|
2259 |
and an 16 character model name. The Linux kernel use the
|
|
2260 |
the SCSI command set to access block devices connected
|
|
2261 |
via USB, IEEE1394 and ATA buses too.
|
|
2262 |
||
2263 |
For ATA disks, the Linux kernel sets the vendor name to "ATA"
|
|
2264 |
and prepends the model name with the real vendor name, but only
|
|
2265 |
if the combined length if not larger than 16. Otherwise the
|
|
2266 |
real vendor name is omitted.
|
|
2267 |
||
2268 |
This method provides a safe way to retrieve the the SCSI vendor
|
|
2269 |
and model name.
|
|
2270 |
||
2271 |
If the vendor name is 'ATA', and if the model name contains
|
|
2272 |
at least one ' ' character, the string before the first ' ' is
|
|
8037.2.1
by Brad Crittenden
fixed annoying typos |
2273 |
returned as the vendor name, and the string after the first
|
7242.2.1
by Abel Deuring
avoid exception when an HWDB submission with an ATA disk with a long product name is processed |
2274 |
' ' is returned as the model name.
|
2275 |
||
2276 |
In all other cases, vendor and model name are returned unmodified.
|
|
2277 |
"""
|
|
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2278 |
vendor = self.scsi_vendor |
7242.2.1
by Abel Deuring
avoid exception when an HWDB submission with an ATA disk with a long product name is processed |
2279 |
if vendor == 'ATA': |
2280 |
# The assumption below that the vendor name does not
|
|
2281 |
# contain any spaces is not necessarily correct, but
|
|
2282 |
# it is hard to find a better heuristic to separate
|
|
2283 |
# the vendor name from the product name.
|
|
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2284 |
splitted_name = self.scsi_model.split(' ', 1) |
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2285 |
if len(splitted_name) == 2: |
2286 |
return { |
|
2287 |
'vendor': splitted_name[0], |
|
2288 |
'product': splitted_name[1], |
|
2289 |
}
|
|
2290 |
return { |
|
2291 |
'vendor': vendor, |
|
2292 |
'product': self.scsi_model, |
|
2293 |
}
|
|
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2294 |
|
2295 |
def getDriver(self): |
|
2296 |
"""Return the HWDriver instance associated with this device.
|
|
2297 |
||
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2298 |
Create a HWDriver record, if it does not already exist.
|
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2299 |
"""
|
2300 |
# HAL and the HWDB client know at present only about kernel
|
|
2301 |
# drivers, so there is currently no need to search for
|
|
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2302 |
# for user space printer drivers, for example.
|
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2303 |
if self.driver_name is not None: |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2304 |
db_driver_set = getUtility(IHWDriverSet) |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2305 |
return db_driver_set.getOrCreate( |
9747.1.4
by Abel Deuring
changed SubmissionParser.getKernelPackageName into property SubmissionParser.kernel_package_name; added code to kernel_package_name to deal with data from HWDB submissions with ude data. |
2306 |
self.parser.kernel_package_name, self.driver_name) |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2307 |
else: |
2308 |
return None |
|
2309 |
||
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2310 |
def ensureVendorIDVendorNameExists(self): |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2311 |
"""Ensure that a useful HWVendorID record for self.vendor_id exists.
|
2312 |
||
2313 |
A vendor ID is associated with a vendor name. For many devices
|
|
2314 |
we rely on the information from the submission to create this
|
|
2315 |
association in the HWVendorID table.
|
|
2316 |
||
2317 |
We do _not_ use the submitted vendor name for USB, PCI and
|
|
2318 |
PCCard devices, because we can get them from independent
|
|
2319 |
sources. See l/c/l/doc/hwdb-device-tables.txt.
|
|
2320 |
"""
|
|
7178.2.2
by Abel Deuring
changed method HALDevice.getRealBus() into property HALDevice.real_bus; fixed a typo |
2321 |
bus = self.real_bus |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2322 |
if (self.vendor is not None and |
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2323 |
bus not in (HWBus.PCI, HWBus.PCCARD, HWBus.USB)): |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2324 |
hw_vendor_id_set = getUtility(IHWVendorIDSet) |
2325 |
hw_vendor_id = hw_vendor_id_set.getByBusAndVendorID( |
|
7272.3.1
by Abel Deuring
fixed a bug in HALDevice.ensureVendorIDVendorNameExists |
2326 |
bus, self.vendor_id_for_db) |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2327 |
if hw_vendor_id is None: |
2328 |
hw_vendor_name_set = getUtility(IHWVendorNameSet) |
|
2329 |
hw_vendor_name = hw_vendor_name_set.getByName(self.vendor) |
|
2330 |
if hw_vendor_name is None: |
|
2331 |
hw_vendor_name = hw_vendor_name_set.create(self.vendor) |
|
2332 |
hw_vendor_id_set.create( |
|
7272.3.1
by Abel Deuring
fixed a bug in HALDevice.ensureVendorIDVendorNameExists |
2333 |
self.real_bus, self.vendor_id_for_db, hw_vendor_name) |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2334 |
|
2335 |
def createDBData(self, submission, parent_submission_device): |
|
2336 |
"""Create HWDB records for this HAL device and its children.
|
|
2337 |
||
2338 |
A HWDevice record for (bus, vendor ID, product ID) of this
|
|
2339 |
device and a HWDeviceDriverLink record (device, None) are
|
|
2340 |
created, if they do not already exist.
|
|
2341 |
||
2342 |
A HWSubmissionDevice record is created for (HWDeviceDriverLink,
|
|
2343 |
submission).
|
|
2344 |
||
2345 |
HWSubmissionDevice records and missing HWDeviceDriverLink
|
|
2346 |
records for known drivers of this device are created.
|
|
2347 |
||
2348 |
createDBData is called recursively for all real child devices.
|
|
2349 |
||
2350 |
This method may only be called, if self.real_device == True.
|
|
2351 |
"""
|
|
2352 |
assert self.is_real_device, ('HALDevice.createDBData must be called ' |
|
2353 |
'for real devices only.') |
|
2354 |
if not self.has_reliable_data: |
|
2355 |
return
|
|
7178.2.2
by Abel Deuring
changed method HALDevice.getRealBus() into property HALDevice.real_bus; fixed a typo |
2356 |
bus = self.real_bus |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2357 |
vendor_id = self.vendor_id_for_db |
2358 |
product_id = self.product_id_for_db |
|
2359 |
product_name = self.product |
|
2360 |
||
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2361 |
self.ensureVendorIDVendorNameExists() |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2362 |
|
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2363 |
db_device = getUtility(IHWDeviceSet).getOrCreate( |
2364 |
bus, vendor_id, product_id, product_name) |
|
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2365 |
# Create a HWDeviceDriverLink record without an associated driver
|
2366 |
# for each real device. This will allow us to relate tests and
|
|
2367 |
# bugs to a device in general as well as to a specific
|
|
2368 |
# combination of a device and a driver.
|
|
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2369 |
device_driver_link = getUtility(IHWDeviceDriverLinkSet).getOrCreate( |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2370 |
db_device, None) |
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2371 |
submission_device = getUtility(IHWSubmissionDeviceSet).create( |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2372 |
device_driver_link, submission, parent_submission_device, |
2373 |
self.id) |
|
2374 |
self.createDBDriverData(submission, db_device, submission_device) |
|
2375 |
||
2376 |
def createDBDriverData(self, submission, db_device, submission_device): |
|
2377 |
"""Create HWDB records for drivers of this device and its children.
|
|
2378 |
||
2379 |
This method creates HWDeviceDriverLink and HWSubmissionDevice
|
|
2380 |
records for this device and its children.
|
|
2381 |
"""
|
|
2382 |
driver = self.getDriver() |
|
2383 |
if driver is not None: |
|
2384 |
device_driver_link_set = getUtility(IHWDeviceDriverLinkSet) |
|
2385 |
device_driver_link = device_driver_link_set.getOrCreate( |
|
2386 |
db_device, driver) |
|
6934.2.2
by Abel Deuring
implemented reviewer's comments |
2387 |
submission_device = getUtility(IHWSubmissionDeviceSet).create( |
6934.2.1
by Abel Deuring
population of HDWB device tables with submission data |
2388 |
device_driver_link, submission, submission_device, self.id) |
2389 |
for sub_device in self.children: |
|
2390 |
if sub_device.is_real_device: |
|
2391 |
sub_device.createDBData(submission, submission_device) |
|
2392 |
else: |
|
2393 |
sub_device.createDBDriverData(submission, db_device, |
|
2394 |
submission_device) |
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2395 |
|
2396 |
||
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2397 |
class HALDevice(BaseDevice): |
2398 |
"""The representation of a HAL device node."""
|
|
2399 |
||
2400 |
def __init__(self, id, udi, properties, parser): |
|
2401 |
"""HALDevice constructor.
|
|
2402 |
||
2403 |
:param id: The ID of the HAL device in the submission data as
|
|
2404 |
specified in <device id=...>.
|
|
2405 |
:type id: int
|
|
2406 |
:param udi: The UDI of the HAL device.
|
|
2407 |
:type udi: string
|
|
2408 |
:param properties: The HAL properties of the device.
|
|
2409 |
:type properties: dict
|
|
2410 |
:param parser: The parser processing a submission.
|
|
2411 |
:type parser: SubmissionParser
|
|
2412 |
"""
|
|
2413 |
super(HALDevice, self).__init__(parser) |
|
2414 |
self.id = id |
|
2415 |
self.udi = udi |
|
2416 |
self.properties = properties |
|
2417 |
||
2418 |
def getProperty(self, property_name): |
|
2419 |
"""Return the HAL property property_name.
|
|
2420 |
||
2421 |
Note that there is no check of the property type.
|
|
2422 |
"""
|
|
2423 |
if property_name not in self.properties: |
|
2424 |
return None |
|
2425 |
name, type_ = self.properties[property_name] |
|
2426 |
return name |
|
2427 |
||
2428 |
@property
|
|
2429 |
def parent_udi(self): |
|
2430 |
"""The UDI of the parent device."""
|
|
2431 |
return self.getProperty('info.parent') |
|
2432 |
||
2433 |
@property
|
|
2434 |
def device_id(self): |
|
2435 |
"""See `BaseDevice`."""
|
|
2436 |
return self.udi |
|
2437 |
||
2438 |
@property
|
|
2439 |
def pci_class(self): |
|
2440 |
"""See `BaseDevice`."""
|
|
2441 |
return self.getProperty('pci.device_class') |
|
2442 |
||
2443 |
@property
|
|
2444 |
def pci_subclass(self): |
|
2445 |
"""The PCI device sub-class of the device or None for Non-PCI devices.
|
|
2446 |
"""
|
|
2447 |
return self.getProperty('pci.device_subclass') |
|
2448 |
||
2449 |
@property
|
|
2450 |
def usb_vendor_id(self): |
|
2451 |
"""See `BaseDevice`."""
|
|
2452 |
return self.getProperty('usb_device.vendor_id') |
|
2453 |
||
2454 |
@property
|
|
2455 |
def usb_product_id(self): |
|
2456 |
"""See `BaseDevice`."""
|
|
2457 |
return self.getProperty('usb_device.product_id') |
|
2458 |
||
2459 |
@property
|
|
2460 |
def scsi_vendor(self): |
|
2461 |
"""See `BaseDevice`."""
|
|
2462 |
return self.getProperty('scsi.vendor') |
|
2463 |
||
2464 |
@property
|
|
2465 |
def scsi_model(self): |
|
2466 |
"""See `BaseDevice`."""
|
|
2467 |
return self.getProperty('scsi.model') |
|
2468 |
||
2469 |
@property
|
|
2470 |
def driver_name(self): |
|
2471 |
"""See `BaseDevice`."""
|
|
2472 |
return self.getProperty('info.linux.driver') |
|
2473 |
||
2474 |
@property
|
|
2475 |
def raw_bus(self): |
|
2476 |
"""See `BaseDevice`."""
|
|
2477 |
# Older versions of HAL stored this value in the property
|
|
2478 |
# info.bus; newer versions store it in info.subsystem.
|
|
2479 |
#
|
|
2480 |
# Note that info.bus is gone for all devices except the
|
|
2481 |
# USB bus. For USB devices, the property info.bus returns more
|
|
2482 |
# detailed data: info.subsystem has the value 'usb' for all
|
|
2483 |
# HAL nodes belonging to USB devices, while info.bus has the
|
|
2484 |
# value 'usb_device' for the root node of a USB device, and the
|
|
2485 |
# value 'usb' for sub-nodes of a USB device. We use these
|
|
2486 |
# different value to to find the root USB device node, hence
|
|
2487 |
# try to read info.bus first.
|
|
2488 |
result = self.getProperty('info.bus') |
|
2489 |
if result is not None: |
|
2490 |
return result |
|
2491 |
return self.getProperty('info.subsystem') |
|
2492 |
||
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
2493 |
@property
|
2494 |
def is_root_device(self): |
|
2495 |
"""See `BaseDevice`."""
|
|
2496 |
return self.udi == ROOT_UDI |
|
2497 |
||
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2498 |
def getVendorOrProduct(self, type_): |
2499 |
"""Return the vendor or product of this device.
|
|
2500 |
||
2501 |
:return: The vendor or product data for this device.
|
|
2502 |
:param type_: 'vendor' or 'product'
|
|
2503 |
"""
|
|
2504 |
# HAL does not store vendor data very consistently. Try to find
|
|
2505 |
# the data in several places.
|
|
2506 |
assert type_ in ('vendor', 'product'), ( |
|
2507 |
'Unexpected value of type_: %r' % type_) |
|
2508 |
||
2509 |
bus = self.raw_bus |
|
2510 |
if self.udi == ROOT_UDI: |
|
2511 |
# HAL sets info.product to "Computer", provides no property
|
|
2512 |
# info.vendor and raw_bus is "unknown", hence the logic
|
|
2513 |
# below does not work properly.
|
|
2514 |
return self.getProperty('system.hardware.' + type_) |
|
2515 |
elif bus == 'scsi': |
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2516 |
return self.getScsiVendorAndModelName()[type_] |
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2517 |
else: |
2518 |
result = self.getProperty('info.' + type_) |
|
2519 |
if result is None: |
|
2520 |
if bus is None: |
|
2521 |
return None |
|
2522 |
else: |
|
2523 |
return self.getProperty('%s.%s' % (bus, type_)) |
|
2524 |
else: |
|
2525 |
return result |
|
2526 |
||
2527 |
@property
|
|
2528 |
def vendor(self): |
|
2529 |
"""See `BaseDevice`."""
|
|
2530 |
return self.getVendorOrProduct('vendor') |
|
2531 |
||
2532 |
@property
|
|
2533 |
def product(self): |
|
2534 |
"""See `BaseDevice`."""
|
|
2535 |
return self.getVendorOrProduct('product') |
|
2536 |
||
2537 |
def getVendorOrProductID(self, type_): |
|
2538 |
"""Return the vendor or product ID for this device.
|
|
2539 |
||
2540 |
:return: The vendor or product ID for this device.
|
|
2541 |
:param type_: 'vendor' or 'product'
|
|
2542 |
"""
|
|
2543 |
assert type_ in ('vendor', 'product'), ( |
|
2544 |
'Unexpected value of type_: %r' % type_) |
|
2545 |
bus = self.raw_bus |
|
2546 |
if self.udi == ROOT_UDI: |
|
2547 |
# HAL does not provide IDs for a system itself, we use the
|
|
2548 |
# vendor resp. product name instead.
|
|
2549 |
return self.getVendorOrProduct(type_) |
|
2550 |
elif bus is None: |
|
2551 |
return None |
|
2552 |
elif bus == 'scsi' or self.udi == ROOT_UDI: |
|
2553 |
# The SCSI specification does not distinguish between a
|
|
2554 |
# vendor/model ID and vendor/model name: the SCSI INQUIRY
|
|
2555 |
# command returns an 8 byte string as the vendor name and
|
|
2556 |
# a 16 byte string as the model name. We use these strings
|
|
2557 |
# as the vendor/product name as well as the vendor/product
|
|
2558 |
# ID.
|
|
2559 |
#
|
|
2560 |
# Similary, HAL does not provide a vendor or product ID
|
|
2561 |
# for the host system itself, so we use the vendor resp.
|
|
2562 |
# product name as the vendor/product ID for systems too.
|
|
2563 |
return self.getVendorOrProduct(type_) |
|
2564 |
else: |
|
2565 |
return self.getProperty('%s.%s_id' % (bus, type_)) |
|
2566 |
||
2567 |
@property
|
|
2568 |
def vendor_id(self): |
|
2569 |
"""See `BaseDevice`."""
|
|
2570 |
return self.getVendorOrProductID('vendor') |
|
2571 |
||
2572 |
@property
|
|
2573 |
def product_id(self): |
|
2574 |
"""See `BaseDevice`."""
|
|
2575 |
return self.getVendorOrProductID('product') |
|
2576 |
||
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
2577 |
@property
|
2578 |
def scsi_controller(self): |
|
2579 |
"""See `BaseDevice`."""
|
|
2580 |
# While SCSI devices from valid submissions should have a
|
|
2581 |
# parent and a grandparent, we can't be sure for bogus or
|
|
2582 |
# broken submissions.
|
|
2583 |
if self.raw_bus != 'scsi': |
|
2584 |
return None |
|
2585 |
parent = self.parent |
|
2586 |
if parent is None: |
|
2587 |
self.parser._logWarning( |
|
2588 |
'Found SCSI device without a parent: %s.' % self.device_id) |
|
2589 |
return None |
|
2590 |
grandparent = parent.parent |
|
2591 |
if grandparent is None: |
|
2592 |
self.parser._logWarning( |
|
2593 |
'Found SCSI device without a grandparent: %s.' |
|
2594 |
% self.device_id) |
|
2595 |
return None |
|
2596 |
return grandparent |
|
2597 |
||
9600.1.5
by Abel Deuring
Refactoring of l.c.l.scripts.hwdbsubmissions.HALDevice, part 3 |
2598 |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2599 |
class UdevDevice(BaseDevice): |
2600 |
"""The representation of a udev device node."""
|
|
2601 |
||
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2602 |
def __init__(self, parser, udev_data, sysfs_data=None, dmi_data=None): |
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2603 |
"""HALDevice constructor.
|
2604 |
||
2605 |
:param udevdata: The udev data for this device
|
|
2606 |
:param sysfs_data: sysfs data for this device.
|
|
2607 |
:param parser: The parser processing a submission.
|
|
2608 |
:type parser: SubmissionParser
|
|
2609 |
"""
|
|
2610 |
super(UdevDevice, self).__init__(parser) |
|
2611 |
self.udev = udev_data |
|
2612 |
self.sysfs = sysfs_data |
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2613 |
self.dmi = dmi_data |
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2614 |
|
2615 |
@property
|
|
2616 |
def device_id(self): |
|
2617 |
"""See `BaseDevice`."""
|
|
2618 |
return self.udev['P'] |
|
2619 |
||
2620 |
@property
|
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2621 |
def root_device_ids(self): |
9685.1.3
by Abel Deuring
fixed a typo |
2622 |
"""The vendor and product IDs of the root device."""
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2623 |
return { |
2624 |
'vendor': self.dmi.get('/sys/class/dmi/id/sys_vendor'), |
|
2625 |
'product': self.dmi.get('/sys/class/dmi/id/product_name') |
|
2626 |
}
|
|
2627 |
||
2628 |
@property
|
|
9644.3.6
by Abel Deuring
implemented reviewer's comments |
2629 |
def is_pci(self): |
2630 |
"""True, if this is a PCI device, else False."""
|
|
2631 |
return self.udev['E'].get('SUBSYSTEM') == 'pci' |
|
2632 |
||
2633 |
@property
|
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2634 |
def pci_class_info(self): |
2635 |
"""Parse the udev property PCI_SUBSYS_ID.
|
|
2636 |
||
2637 |
:return: (PCI class, PCI sub-class, version) for a PCI device
|
|
2638 |
or (None, None, None) for other devices.
|
|
2639 |
"""
|
|
9644.3.6
by Abel Deuring
implemented reviewer's comments |
2640 |
if self.is_pci: |
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2641 |
# SubmissionParser.checkConsistentUdevDeviceData() ensures
|
2642 |
# that PCI_CLASS is a 24 bit integer in hexadecimal
|
|
2643 |
# representation.
|
|
9644.3.6
by Abel Deuring
implemented reviewer's comments |
2644 |
# Bits 16..23 of the number are the man PCI class,
|
2645 |
# bits 8..15 are the sub-class, bits 0..7 are the version.
|
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2646 |
class_info = int(self.udev['E']['PCI_CLASS'], 16) |
2647 |
return (class_info >> 16, (class_info >> 8) & 0xFF, |
|
2648 |
class_info & 0xFF) |
|
2649 |
else: |
|
2650 |
return (None, None, None) |
|
2651 |
||
2652 |
@property
|
|
2653 |
def pci_class(self): |
|
2654 |
"""See `BaseDevice`."""
|
|
2655 |
return self.pci_class_info[0] |
|
2656 |
||
2657 |
@property
|
|
2658 |
def pci_subclass(self): |
|
2659 |
"""See `BaseDevice`."""
|
|
2660 |
return self.pci_class_info[1] |
|
2661 |
||
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2662 |
@property
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2663 |
def pci_ids(self): |
2664 |
"""The PCI vendor and product IDs.
|
|
2665 |
||
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2666 |
:return: A dictionary containing the vendor and product IDs.
|
2667 |
The IDs are set to None for Non-PCI devices.
|
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2668 |
"""
|
2669 |
if self.is_pci: |
|
2670 |
# SubmissionParser.checkUdevPciProperties() ensures that
|
|
2671 |
# each PCI device has the property PCI_ID and that is
|
|
2672 |
# consists of two 4-digit hexadecimal numbers, separated
|
|
2673 |
# by a ':'.
|
|
2674 |
id_string = self.udev['E']['PCI_ID'] |
|
2675 |
ids = id_string.split(':') |
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2676 |
return { |
2677 |
'vendor': int(ids[0], 16), |
|
2678 |
'product': int(ids[1], 16), |
|
2679 |
}
|
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2680 |
else: |
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2681 |
return { |
2682 |
'vendor': None, |
|
2683 |
'product': None, |
|
2684 |
}
|
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2685 |
|
2686 |
@property
|
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2687 |
def is_usb(self): |
2688 |
"""True, if this is a USB device, else False."""
|
|
2689 |
return self.udev['E'].get('SUBSYSTEM') == 'usb' |
|
2690 |
||
2691 |
@property
|
|
2692 |
def usb_ids(self): |
|
2693 |
"""The vendor ID, product ID, product version for USB devices.
|
|
2694 |
||
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2695 |
:return: A dictionary containing the vendor and product IDs and
|
2696 |
the product version for USB devices.
|
|
2697 |
The IDs are set to None for Non-USB devices.
|
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2698 |
"""
|
2699 |
if self.is_usb: |
|
2700 |
# udev represents USB device IDs as strings
|
|
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
2701 |
# vendor_id/product_id/version, where each part is
|
2702 |
# a hexadecimal number.
|
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2703 |
# SubmissionParser.checkUdevUsbProperties() ensures that
|
2704 |
# the string PRODUCT is in the format required below.
|
|
2705 |
product_info = self.udev['E']['PRODUCT'].split('/') |
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2706 |
return { |
2707 |
'vendor': int(product_info[0], 16), |
|
2708 |
'product': int(product_info[1], 16), |
|
2709 |
'version': int(product_info[2], 16), |
|
2710 |
}
|
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2711 |
else: |
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2712 |
return { |
2713 |
'vendor': None, |
|
2714 |
'product': None, |
|
2715 |
'version': None, |
|
2716 |
}
|
|
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2717 |
|
2718 |
@property
|
|
2719 |
def usb_vendor_id(self): |
|
2720 |
"""See `BaseDevice`."""
|
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2721 |
return self.usb_ids['vendor'] |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2722 |
|
2723 |
@property
|
|
2724 |
def usb_product_id(self): |
|
2725 |
"""See `BaseDevice`."""
|
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2726 |
return self.usb_ids['product'] |
9644.3.7
by Abel Deuring
sanity checks for USB data in HWDB submissions with udev as the data source; USB-related properties for class UdevDevice |
2727 |
|
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
2728 |
@property
|
2729 |
def is_scsi_device(self): |
|
9644.3.10
by Abel Deuring
mplemented reveiwer's comments |
2730 |
"""True, if this is a SCSI device, else False."""
|
9644.3.9
by Abel Deuring
sanity checks for SCSI and DMI data in HWDB subimissions with udev as the data source; SCSI-related properties for class UdevDevice |
2731 |
# udev sets the property SUBSYSTEM to "scsi" for a number of
|
2732 |
# different nodes: SCSI hosts, SCSI targets and SCSI devices.
|
|
2733 |
# They are distiguished by the property DEVTYPE.
|
|
2734 |
properties = self.udev['E'] |
|
2735 |
return (properties.get('SUBSYSTEM') == 'scsi' and |
|
2736 |
properties.get('DEVTYPE') == 'scsi_device') |
|
2737 |
||
2738 |
@property
|
|
2739 |
def scsi_vendor(self): |
|
2740 |
"""The SCSI vendor name of the device or None for Non-SCSI devices."""
|
|
2741 |
if self.is_scsi_device: |
|
2742 |
# SubmissionParser.checkUdevScsiProperties() ensures that
|
|
2743 |
# each SCSI device has a record in self.sysfs and that
|
|
2744 |
# the attribute 'vendor' exists.
|
|
2745 |
path = self.udev['P'] |
|
2746 |
return self.sysfs['vendor'] |
|
2747 |
else: |
|
2748 |
return None |
|
2749 |
||
2750 |
@property
|
|
2751 |
def scsi_model(self): |
|
2752 |
"""The SCSI model name of the device or None for Non-SCSI devices."""
|
|
2753 |
if self.is_scsi_device: |
|
2754 |
# SubmissionParser.checkUdevScsiProperties() ensures that
|
|
2755 |
# each SCSI device has a record in self.sysfs and that
|
|
2756 |
# the attribute 'model' exists.
|
|
2757 |
path = self.udev['P'] |
|
2758 |
return self.sysfs['model'] |
|
2759 |
else: |
|
2760 |
return None |
|
2761 |
||
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2762 |
@property
|
2763 |
def raw_bus(self): |
|
2764 |
"""See `BaseDevice`."""
|
|
2765 |
# udev specifies the property SUBSYSTEM for most devices;
|
|
2766 |
# some devices have additionally the more specific property
|
|
2767 |
# DEVTYPE. DEVTYPE is preferable.
|
|
2768 |
# The root device has the subsystem/bus value "acpi", which
|
|
2769 |
# is a bit nonsensical.
|
|
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
2770 |
if self.is_root_device: |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2771 |
return None |
2772 |
properties = self.udev['E'] |
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2773 |
devtype = properties.get('DEVTYPE') |
2774 |
if devtype is not None: |
|
2775 |
return devtype |
|
9710.4.2
by Abel Deuring
Adjusted BaseDevice.is_real_device for HWDB submissions with udev data; tests for this property with udev data |
2776 |
subsystem = properties.get('SUBSYSTEM') |
2777 |
# A real mess: The main node of a SCSI device has
|
|
2778 |
# SUBSYSTEM = 'scsi' and DEVTYPE = 'scsi_device', while
|
|
2779 |
# a sub-node has SUBSYSTEM='scsi_device'. We don't want
|
|
2780 |
# the two to be confused. The latter node is not of any
|
|
2781 |
# interest for us, so we return None. This ensures that
|
|
2782 |
# is_real_device returns False for the sub-node.
|
|
2783 |
if subsystem != 'scsi_device': |
|
2784 |
return subsystem |
|
2785 |
else: |
|
2786 |
return None |
|
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2787 |
|
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
2788 |
@property
|
2789 |
def is_root_device(self): |
|
2790 |
"""See `BaseDevice`."""
|
|
2791 |
return self.udev['P'] == UDEV_ROOT_PATH |
|
2792 |
||
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2793 |
def getVendorOrProduct(self, type_): |
2794 |
"""Return the vendor or product of this device.
|
|
2795 |
||
2796 |
:return: The vendor or product data for this device.
|
|
2797 |
:param type_: 'vendor' or 'product'
|
|
2798 |
"""
|
|
2799 |
assert type_ in ('vendor', 'product'), ( |
|
2800 |
'Unexpected value of type_: %r' % type_) |
|
2801 |
||
2802 |
bus = self.raw_bus |
|
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
2803 |
if self.is_root_device: |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2804 |
# udev does not known about any product information for
|
2805 |
# the root device. We use DMI data instead.
|
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2806 |
return self.root_device_ids[type_] |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2807 |
elif bus == 'scsi_device': |
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2808 |
return self.getScsiVendorAndModelName()[type_] |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2809 |
elif bus in ('pci', 'usb_device'): |
2810 |
# XXX Abel Deuring 2009-10-13, bug 450480: udev does not
|
|
2811 |
# provide human-readable vendor and product names for
|
|
2812 |
# USB and PCI devices. We should retrieve these from
|
|
2813 |
# http://www.linux-usb.org/usb.ids and
|
|
2814 |
# http://pciids.sourceforge.net/v2.2/pci.ids
|
|
2815 |
return 'Unknown' |
|
2816 |
else: |
|
2817 |
# We don't process yet other devices than complete systems,
|
|
2818 |
# PCI, USB devices and those devices that are represented
|
|
2819 |
# in udev as SCSI devices: real SCSI devices, and
|
|
2820 |
# IDE/ATA/SATA devices.
|
|
2821 |
return None |
|
2822 |
||
2823 |
@property
|
|
2824 |
def vendor(self): |
|
2825 |
"""See `BaseDevice`."""
|
|
2826 |
return self.getVendorOrProduct('vendor') |
|
2827 |
||
2828 |
@property
|
|
2829 |
def product(self): |
|
2830 |
"""See `BaseDevice`."""
|
|
2831 |
return self.getVendorOrProduct('product') |
|
2832 |
||
2833 |
def getVendorOrProductID(self, type_): |
|
2834 |
"""Return the vendor or product ID of this device.
|
|
2835 |
||
2836 |
:return: The vendor or product ID for this device.
|
|
2837 |
:param type_: 'vendor' or 'product'
|
|
2838 |
"""
|
|
2839 |
assert type_ in ('vendor', 'product'), ( |
|
2840 |
'Unexpected value of type_: %r' % type_) |
|
2841 |
||
2842 |
bus = self.raw_bus |
|
9691.1.4
by Abel Deuring
fixed test data for Udev USB storage device; new property is_root_device for class BaseDevice; adapted BaseDevice.real_device for UdevDevice; tests for BaseDevice.real_device and for BaseDevice.translatePciBus() with udev data |
2843 |
if self.is_root_device: |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2844 |
# udev does not known about any product information for
|
2845 |
# the root device. We use DMI data instead.
|
|
2846 |
if type_ == 'vendor': |
|
2847 |
return self.dmi.get('/sys/class/dmi/id/sys_vendor') |
|
2848 |
else: |
|
2849 |
return self.dmi.get('/sys/class/dmi/id/product_name') |
|
2850 |
elif bus == 'scsi_device': |
|
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2851 |
return self.getScsiVendorAndModelName()[type_] |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2852 |
elif bus == 'pci': |
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2853 |
return self.pci_ids[type_] |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2854 |
elif bus == 'usb_device': |
9685.1.2
by Abel Deuring
implemented reveiwer's comments |
2855 |
return self.usb_ids[type_] |
9685.1.1
by Abel Deuring
properties pci_ids, raw_bus, vendor, vendor_id, product, product_id for class UdevDevice |
2856 |
else: |
2857 |
# We don't process yet other devices than complete systems,
|
|
2858 |
# PCI, USB devices and those devices that are represented
|
|
2859 |
# in udev as SCSI devices: real SCSI devices, and
|
|
2860 |
# IDE/ATA/SATA devices.
|
|
2861 |
return None |
|
2862 |
||
2863 |
@property
|
|
2864 |
def vendor_id(self): |
|
2865 |
"""See `BaseDevice`."""
|
|
2866 |
return self.getVendorOrProductID('vendor') |
|
2867 |
||
2868 |
@property
|
|
2869 |
def product_id(self): |
|
2870 |
"""See `BaseDevice`."""
|
|
2871 |
return self.getVendorOrProductID('product') |
|
2872 |
||
9691.1.1
by Abel Deuring
properties UdevDevice.vendor_id_for_db, UdevDevice.product_id_for_db fixed; new property Udev.driver_name; refactored BaseDevice.translateScsiBus(); new property BaseDevice.scsi_controller |
2873 |
@property
|
2874 |
def driver_name(self): |
|
2875 |
"""See `BaseDevice`."""
|
|
2876 |
return self.udev['E'].get('DRIVER') |
|
2877 |
||
9691.1.2
by Abel Deuring
Property UdevDevcie.scsi_controller; tests for UdevDevice.translateScsiBus() |
2878 |
@property
|
2879 |
def scsi_controller(self): |
|
2880 |
"""See `BaseDevice`."""
|
|
2881 |
if self.raw_bus != 'scsi_device': |
|
2882 |
return None |
|
2883 |
||
9691.1.3
by Abel Deuring
implemented reviewar's comments |
2884 |
# While SCSI devices from valid submissions should have four
|
2885 |
# ancestors, we can't be sure for bogus or broken submissions.
|
|
2886 |
try: |
|
9710.4.1
by Abel Deuring
serious bug in UdevDevice.scsi_controller fixed; TestUdevDevice.buildUdevDeviceHierarchy() now builds the parent-child relations based on the device paths and returns a dict instead of a list. Affected tests updated |
2887 |
controller = self.parent.parent.parent |
9691.1.3
by Abel Deuring
implemented reviewar's comments |
2888 |
except AttributeError: |
2889 |
controller = None |
|
2890 |
if controller is None: |
|
2891 |
self.parser._logWarning( |
|
2892 |
'Found a SCSI device without a sufficient number of '
|
|
2893 |
'ancestors: %s' % self.device_id) |
|
2894 |
return None |
|
2895 |
return controller |
|
9644.3.1
by Abel Deuring
more sanity checks for HWDB submissions with udev data; new class UdevDevice defiend |
2896 |
|
9747.1.1
by Abel Deuring
Property UdevDevice.id added |
2897 |
@property
|
2898 |
def id(self): |
|
2899 |
return self.udev['id'] |
|
2900 |
||
2901 |
||
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2902 |
class ProcessingLoop(object): |
2903 |
"""An `ITunableLoop` for processing HWDB submissions."""
|
|
2904 |
||
2905 |
implements(ITunableLoop) |
|
2906 |
||
2907 |
def __init__(self, transaction, logger, max_submissions): |
|
2908 |
self.transaction = transaction |
|
2909 |
self.logger = logger |
|
2910 |
self.max_submissions = max_submissions |
|
2911 |
self.valid_submissions = 0 |
|
2912 |
self.invalid_submissions = 0 |
|
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2913 |
self.finished = False |
7508.1.1
by Abel Deuring
fix for bug 314342: HWDB submission processing script does not process private submissions |
2914 |
self.janitor = getUtility(ILaunchpadCelebrities).janitor |
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2915 |
|
2916 |
def _validateSubmission(self, submission): |
|
2917 |
submission.status = HWSubmissionProcessingStatus.PROCESSED |
|
2918 |
self.valid_submissions += 1 |
|
2919 |
||
2920 |
def _invalidateSubmission(self, submission): |
|
2921 |
submission.status = HWSubmissionProcessingStatus.INVALID |
|
2922 |
self.invalid_submissions += 1 |
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2923 |
|
2924 |
def isDone(self): |
|
2925 |
"""See `ITunableLoop`."""
|
|
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2926 |
return self.finished |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2927 |
|
7881.6.1
by Abel Deuring
Better handling of errors in the HWDB submission processing script that are caused by a non-responding Librarian |
2928 |
def reportOops(self, error_explanation): |
2929 |
"""Create an OOPS report and the OOPS ID."""
|
|
2930 |
info = sys.exc_info() |
|
2931 |
properties = [('error-explanation', error_explanation)] |
|
2932 |
request = ScriptRequest(properties) |
|
2933 |
error_utility = ErrorReportingUtility() |
|
2934 |
error_utility.raising(info, request) |
|
2935 |
self.logger.error('%s (%s)' % (error_explanation, request.oopsid)) |
|
2936 |
||
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2937 |
def __call__(self, chunk_size): |
2938 |
"""Process a batch of yet unprocessed HWDB submissions."""
|
|
7123.1.1
by Abel Deuring
two embarassing bugs in the loop management of the HWDB processing script fixed |
2939 |
# chunk_size is a float; we compare it below with an int value,
|
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2940 |
# which can lead to unexpected results. Since it is also used as
|
7123.1.3
by Abel Deuring
implenented reviewer's comments |
2941 |
# a limit for an SQL query, convert it into an integer.
|
7123.1.1
by Abel Deuring
two embarassing bugs in the loop management of the HWDB processing script fixed |
2942 |
chunk_size = int(chunk_size) |
2943 |
submissions = getUtility(IHWSubmissionSet).getByStatus( |
|
7508.1.1
by Abel Deuring
fix for bug 314342: HWDB submission processing script does not process private submissions |
2944 |
HWSubmissionProcessingStatus.SUBMITTED, |
2945 |
user=self.janitor |
|
2946 |
)[:chunk_size] |
|
7554.1.1
by Bjorn Tillenius
get rid of a COUNT query. |
2947 |
# Listify the submissions, since we'll have to loop over each
|
2948 |
# one anyway. This saves a COUNT query for getting the number of
|
|
2949 |
# submissions
|
|
2950 |
submissions = list(submissions) |
|
2951 |
if len(submissions) < chunk_size: |
|
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2952 |
self.finished = True |
7881.6.1
by Abel Deuring
Better handling of errors in the HWDB submission processing script that are caused by a non-responding Librarian |
2953 |
|
2954 |
# Note that we must either change the status of each submission
|
|
2955 |
# in the loop below or we must abort the submission processing
|
|
2956 |
# entirely: getUtility(IHWSubmissionSet).getByStatus() above
|
|
2957 |
# returns the oldest submissions first, so if one submission
|
|
2958 |
# would remain in the status SUBMITTED, it would be returned
|
|
2959 |
# in the next loop run again, leading to a potentially endless
|
|
2960 |
# loop.
|
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2961 |
for submission in submissions: |
2962 |
try: |
|
2963 |
parser = SubmissionParser(self.logger) |
|
2964 |
success = parser.processSubmission(submission) |
|
2965 |
if success: |
|
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2966 |
self._validateSubmission(submission) |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2967 |
else: |
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2968 |
self._invalidateSubmission(submission) |
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2969 |
except (KeyboardInterrupt, SystemExit): |
2970 |
# We should never catch these exceptions.
|
|
2971 |
raise
|
|
7881.6.1
by Abel Deuring
Better handling of errors in the HWDB submission processing script that are caused by a non-responding Librarian |
2972 |
except LibrarianServerError, error: |
7881.6.4
by Abel Deuring
re-implementation of handling Librarian errors in scripts/hwdbsubmissions.py, based on better error handling in FileDownloadClient.getFileByAlias(). |
2973 |
# LibrarianServerError is raised when the server could
|
2974 |
# not be reaches for 30 minutes.
|
|
2975 |
#
|
|
7881.6.1
by Abel Deuring
Better handling of errors in the HWDB submission processing script that are caused by a non-responding Librarian |
2976 |
# In this case we can neither validate nor invalidate the
|
2977 |
# submission. Moreover, the attempt to process the next
|
|
2978 |
# submission will most likely also fail, so we should give
|
|
2979 |
# up for now.
|
|
7881.6.4
by Abel Deuring
re-implementation of handling Librarian errors in scripts/hwdbsubmissions.py, based on better error handling in FileDownloadClient.getFileByAlias(). |
2980 |
#
|
7881.6.1
by Abel Deuring
Better handling of errors in the HWDB submission processing script that are caused by a non-responding Librarian |
2981 |
# This exception is raised before any data for the current
|
2982 |
# submission is processed, hence we can commit submissions
|
|
2983 |
# processed in previous runs of this loop without causing
|
|
2984 |
# any inconsistencies.
|
|
2985 |
self.transaction.commit() |
|
2986 |
||
2987 |
self.reportOops( |
|
2988 |
'Could not reach the Librarian while processing HWDB '
|
|
2989 |
'submission %s' % submission.submission_key) |
|
2990 |
raise
|
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2991 |
except Exception, error: |
7881.6.1
by Abel Deuring
Better handling of errors in the HWDB submission processing script that are caused by a non-responding Librarian |
2992 |
self.transaction.abort() |
2993 |
self.reportOops( |
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
2994 |
'Exception while processing HWDB submission %s' |
2995 |
% submission.submission_key) |
|
2996 |
||
7123.1.2
by Abel Deuring
implemented reviewer's comments |
2997 |
self._invalidateSubmission(submission) |
7123.1.1
by Abel Deuring
two embarassing bugs in the loop management of the HWDB processing script fixed |
2998 |
# Ensure that this submission is marked as bad, even if
|
2999 |
# further submissions in this batch raise an exception.
|
|
3000 |
self.transaction.commit() |
|
3001 |
||
3002 |
if self.max_submissions is not None: |
|
3003 |
if self.max_submissions <= ( |
|
3004 |
self.valid_submissions + self.invalid_submissions): |
|
7123.1.2
by Abel Deuring
implemented reviewer's comments |
3005 |
self.finished = True |
7123.1.1
by Abel Deuring
two embarassing bugs in the loop management of the HWDB processing script fixed |
3006 |
break
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
3007 |
self.transaction.commit() |
3008 |
||
3009 |
def process_pending_submissions(transaction, logger, max_submissions=None): |
|
3010 |
"""Process pending submissions.
|
|
3011 |
||
3012 |
Parse pending submissions, store extracted data in HWDB tables and
|
|
3013 |
mark them as either PROCESSED or INVALID.
|
|
3014 |
"""
|
|
3015 |
loop = ProcessingLoop(transaction, logger, max_submissions) |
|
7123.1.3
by Abel Deuring
implenented reviewer's comments |
3016 |
# It is hard to predict how long it will take to parse a submission.
|
3017 |
# we don't want to last a DB transaction too long but we also
|
|
3018 |
# don't want to commit more often than necessary. The LoopTuner
|
|
3019 |
# handles this for us. The loop's run time will be approximated to
|
|
3020 |
# 2 seconds, but will never handle more than 50 submissions.
|
|
7123.1.1
by Abel Deuring
two embarassing bugs in the loop management of the HWDB processing script fixed |
3021 |
loop_tuner = LoopTuner( |
3022 |
loop, 2, minimum_chunk_size=1, maximum_chunk_size=50) |
|
6978.2.7
by Abel Deuring
method added to class SubmissionParser that ties together all processing steps, ITunableLoop added for batch processing; more test data added |
3023 |
loop_tuner.run() |
3024 |
logger.info( |
|
3025 |
'Processed %i valid and %i invalid HWDB submissions' |
|
3026 |
% (loop.valid_submissions, loop.invalid_submissions)) |