diff --git a/const.py b/const.py new file mode 100644 index 0000000000000000000000000000000000000000..bac3f747c819f4c6a3ae8244c86fc9a8f6b6695b --- /dev/null +++ b/const.py @@ -0,0 +1,47 @@ +from enum import Enum + + +class MSFTDiskBusType(Enum): + UNKNOWN = 0 + SCSI = 1 + ATAPI = 2 + ATA = 3 + IEEE_1394 = 4 + SSA = 5 + FIBER_CHANNEL = 6 + USB = 7 + RAID = 8 + iSCSI = 9 + SAS = 10 + SATA = 11 + SD = 12 + MMC = 13 + _SYSTEM_RESERVED_14 = 14 + FILE_BACKUP_VIRTUAL = 15 + STORAGE_SPACE = 16 + NVMe = 17 + _SYSTEM_RESERVED_18 = 18 + + @classmethod + def whitelist(cls): + return set([ + MSFTDiskBusType.SCSI, + MSFTDiskBusType.ATA, + MSFTDiskBusType.iSCSI, + MSFTDiskBusType.SAS, + MSFTDiskBusType.SATA, + MSFTDiskBusType.NVMe, + ]) + +class MSFTDiskMediaType(Enum): + UNSPECIFIED = 0 + HDD = 3 + SSD = 4 + SCM = 5 + + @classmethod + def whitelist(cls): + return set([ + MSFTDiskMediaType.HDD, + MSFTDiskMediaType.SSD, + ]) diff --git a/parse.py b/parse.py index 08d64bfcc673cd7ff9f4e49485fc85b7c708c63e..d1e355f6022be8595544b8018e98adcbf4150653 100644 --- a/parse.py +++ b/parse.py @@ -1,7 +1,18 @@ import os import re +import sys import xml.etree.ElementTree as ET +import const + + +HACK_NOTE = dict() +_hacknote_filename = os.getenv("HWINFO_HACKNOTE_FILE", "hacknote.json") +if os.path.exists(_hacknote_filename): + import json + HACK_NOTE = json.load(open(_hacknote_filename, encoding="utf-8")) + print("Loaded {:,} keys from hack note".format(len(HACK_NOTE))) + def parse_single(body): stripped = body @@ -16,7 +27,11 @@ def parse_single(body): for search in doc.findall("search"): query = search.find("query") - part_type = query.text.lower().split(' win32_')[-1] + + if "MSFT" in query.text: + part_type = query.text.lower().split("_")[-1] + else: + part_type = query.text.lower().split(' win32_')[-1] if part_type not in parsed: parsed[part_type] = [] @@ -137,6 +152,39 @@ def parser_disk(_tree): } +def parser_disk_meta(_tree): + name = extract_tag(_tree, ("Model", "FriendlyName",)) + capacity = failsafe(int, extract_tag(_tree, ("Size",))) + _media_type = failsafe(int, extract_tag(_tree, ("MediaType",))) + _bus_type = failsafe(int, extract_tag(_tree, ("BusType",))) + serial = extract_tag(_tree, ("SerialNumber",)) + + if isinstance(capacity, int): + capacity = readable(capacity, base=1000) + + media_type = None + try: + media_type = const.MSFTDiskMediaType(_media_type) + except: + print("Unknown disk media type", _media_type, file=sys.stderr) + pass + + bus_type = None + try: + bus_type = const.MSFTDiskBusType(_bus_type) + except: + print("Unknown disk bus type", _bus_type, file=sys.stderr) + pass + + return { + "name": name, + "capacity": capacity, + "media_type": media_type, + "bus_type": bus_type, + "serial": serial, + } + + def parser_gpu(_tree): name = extract_tag(_tree, ("Name", "VideoProcessor", "Caption",)) manufacturer = extract_tag(_tree, ("AdapterCompatibility",)) @@ -177,22 +225,71 @@ def handle_xml_body(data): tree = parse_single(data) cpu_name = filter_virtual([parse_cpu(_doc) for _doc in tree['processor']]) - disks_name = filter_virtual([parser_disk(_doc) for _doc in tree['diskdrive']]) board_name = filter_virtual([parser_mb(tree['baseboard'][0])]) memory_name = filter_virtual([parser_mem(_doc) for _doc in tree['physicalmemory']]) gpu_name = filter_virtual([parser_gpu(_doc) for _doc in tree['videocontroller']]) + disk_name = filter_virtual([parser_disk(_doc) for _doc in tree['diskdrive']]) + _disk_meta = filter_virtual([parser_disk_meta(_doc) for _doc in tree['physicaldisk']]) \ + if 'physicaldisk' in tree else [] + + _disk_meta_dict = dict((x.get('name') or None, x,) for x in _disk_meta) + + for _part in disk_name: + _part["type"] = None + _part["interface"] = None + + _part_name = _part.get('name') + if not _part_name: + continue + + if _part_name in HACK_NOTE: + _note = HACK_NOTE[_part_name] + _media_type = const.MSFTDiskMediaType(_note['media_type']) + _bus_type = const.MSFTDiskBusType(_note["bus_type"]) + + else: + _part_meta = _disk_meta_dict.get(_part_name) + if not _part_meta: + continue + + _media_type = _part_meta['media_type'] + _bus_type = _part_meta["bus_type"] + + if _media_type not in const.MSFTDiskMediaType.whitelist(): + print("Ignorin ", _part_name, "due to not whitelisted device media type", _media_type, file=sys.stderr) + continue + + _part["type"] = _media_type.name + + if _bus_type not in const.MSFTDiskBusType.whitelist(): + print("Ignorin ", _part_name, "due to not whitelisted device bus type", _bus_type, file=sys.stderr) + continue + + _part["interface"] = _bus_type.name + + return { "CPU": cpu_name, "MB": board_name, "RAM": memory_name, - "DISK": disks_name, + "DISK": disk_name, "GPU": gpu_name, } if __name__ == "__main__": files = list(filter(lambda x: x.startswith("meanspec-log"), os.listdir())) + _meta_required = set() + for fname in files: - print(fname, handle_xml(fname)) + print(fname) + parsed = handle_file(fname) + print(parsed["DISK"]) + print() + + for _disk in parsed["DISK"]: + if not _disk["interface"] or not _disk["type"]: + _meta_required.add(_disk["name"]) + [print(x) for x in _meta_required]