mirror of
https://github.com/sickcodes/Docker-OSX.git
synced 2025-06-21 17:12:47 +02:00
140 lines
6.3 KiB
Python
140 lines
6.3 KiB
Python
# linux_hardware_info.py
|
|
import subprocess
|
|
import re
|
|
|
|
def _run_command(command: list[str]) -> str:
|
|
"""Helper to run a command and return its stdout."""
|
|
try:
|
|
process = subprocess.run(command, capture_output=True, text=True, check=True)
|
|
return process.stdout
|
|
except FileNotFoundError:
|
|
print(f"Error: Command '{command[0]}' not found. Is 'pciutils' (for lspci) installed?")
|
|
return ""
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error executing {' '.join(command)}: {e.stderr}")
|
|
return ""
|
|
except Exception as e:
|
|
print(f"An unexpected error occurred with command {' '.join(command)}: {e}")
|
|
return ""
|
|
|
|
def get_pci_devices_info() -> list[dict]:
|
|
"""
|
|
Gets a list of dictionaries, each containing info about a PCI device,
|
|
focusing on VGA, Audio, and Ethernet controllers.
|
|
Output format for relevant devices:
|
|
{'type': 'VGA', 'vendor_id': '10de', 'device_id': '13c2', 'description': 'NVIDIA GTX 970'}
|
|
{'type': 'Audio', 'vendor_id': '8086', 'device_id': 'a170', 'description': 'Intel Sunrise Point-H HD Audio'}
|
|
{'type': 'Ethernet', 'vendor_id': '8086', 'device_id': '15b8', 'description': 'Intel Ethernet Connection I219-V'}
|
|
"""
|
|
output = _run_command(["lspci", "-nnk"])
|
|
if not output:
|
|
return []
|
|
|
|
devices = []
|
|
# Regex to capture device type (from description), description, and [vendor:device]
|
|
# Example line: 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1)
|
|
# Example line: 00:1f.3 Audio device [0403]: Intel Corporation Sunrise Point-H HD Audio [8086:a170] (rev 31)
|
|
# Example line: 00:1f.6 Ethernet controller [0200]: Intel Corporation Ethernet Connection (2) I219-V [8086:15b8] (rev 31)
|
|
|
|
# More robust regex:
|
|
# It captures the class description (like "VGA compatible controller", "Audio device")
|
|
# and the main device description (like "NVIDIA Corporation GM204 [GeForce GTX 970]")
|
|
# and the vendor/device IDs like "[10de:13c2]"
|
|
regex = re.compile(
|
|
r"^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.\d\s+" # PCI Address (e.g., 01:00.0 )
|
|
r"(.+?)\s+" # Class Description (e.g., "VGA compatible controller")
|
|
r"\[[0-9a-fA-F]{4}\]:\s+" # PCI Class Code (e.g., [0300]: )
|
|
r"(.+?)\s+" # Full Device Description (e.g., "NVIDIA Corporation GM204 [GeForce GTX 970]")
|
|
r"\[([0-9a-fA-F]{4}):([0-9a-fA-F]{4})\]" # Vendor and Device ID (e.g., [10de:13c2])
|
|
)
|
|
|
|
for line in output.splitlines():
|
|
match = regex.search(line)
|
|
if match:
|
|
class_desc = match.group(1).strip()
|
|
full_desc = match.group(2).strip()
|
|
vendor_id = match.group(3).lower()
|
|
device_id = match.group(4).lower()
|
|
|
|
device_type = None
|
|
if "VGA compatible controller" in class_desc or "3D controller" in class_desc:
|
|
device_type = "VGA"
|
|
elif "Audio device" in class_desc:
|
|
device_type = "Audio"
|
|
elif "Ethernet controller" in class_desc:
|
|
device_type = "Ethernet"
|
|
elif "Network controller" in class_desc: # Could be Wi-Fi
|
|
device_type = "Network (Wi-Fi?)"
|
|
|
|
|
|
if device_type:
|
|
# Try to get a cleaner description if possible, removing vendor name if it's at the start
|
|
# e.g. "Intel Corporation Ethernet Connection (2) I219-V" -> "Ethernet Connection (2) I219-V"
|
|
# This is a simple attempt.
|
|
cleaned_desc = full_desc
|
|
if full_desc.lower().startswith("intel corporation "):
|
|
cleaned_desc = full_desc[len("intel corporation "):]
|
|
elif full_desc.lower().startswith("nvidia corporation "):
|
|
cleaned_desc = full_desc[len("nvidia corporation "):]
|
|
elif full_desc.lower().startswith("advanced micro devices, inc.") or full_desc.lower().startswith("amd"):
|
|
# Handle different AMD namings
|
|
if full_desc.lower().startswith("advanced micro devices, inc."):
|
|
cleaned_desc = re.sub(r"Advanced Micro Devices, Inc\.\s*\[AMD/ATI\]\s*", "", full_desc, flags=re.IGNORECASE)
|
|
else: # Starts with AMD
|
|
cleaned_desc = re.sub(r"AMD\s*\[ATI\]\s*", "", full_desc, flags=re.IGNORECASE)
|
|
elif full_desc.lower().startswith("realtek semiconductor co., ltd."):
|
|
cleaned_desc = full_desc[len("realtek semiconductor co., ltd. "):]
|
|
|
|
|
|
devices.append({
|
|
"type": device_type,
|
|
"vendor_id": vendor_id,
|
|
"device_id": device_id,
|
|
"description": cleaned_desc.strip(),
|
|
"full_lspci_line": line.strip() # For debugging or more info
|
|
})
|
|
return devices
|
|
|
|
def get_cpu_info() -> dict:
|
|
"""
|
|
Gets CPU information using lscpu.
|
|
Returns a dictionary with 'Model name', 'Vendor ID', 'CPU family', 'Model', 'Stepping', 'Flags'.
|
|
"""
|
|
output = _run_command(["lscpu"])
|
|
if not output:
|
|
return {}
|
|
|
|
info = {}
|
|
# Regex to capture key-value pairs from lscpu output
|
|
# Handles spaces in values for "Model name"
|
|
regex = re.compile(r"^(CPU family|Model name|Vendor ID|Model|Stepping|Flags):\s+(.*)$")
|
|
for line in output.splitlines():
|
|
match = regex.match(line)
|
|
if match:
|
|
key = match.group(1).strip()
|
|
value = match.group(2).strip()
|
|
info[key] = value
|
|
return info
|
|
|
|
|
|
if __name__ == '__main__':
|
|
print("--- PCI Devices ---")
|
|
pci_devs = get_pci_devices_info()
|
|
if pci_devs:
|
|
for dev in pci_devs:
|
|
print(f" Type: {dev['type']}")
|
|
print(f" Vendor ID: {dev['vendor_id']}")
|
|
print(f" Device ID: {dev['device_id']}")
|
|
print(f" Description: {dev['description']}")
|
|
# print(f" Full Line: {dev['full_lspci_line']}")
|
|
else:
|
|
print(" No relevant PCI devices found or lspci not available.")
|
|
|
|
print("\n--- CPU Info ---")
|
|
cpu_info = get_cpu_info()
|
|
if cpu_info:
|
|
for key, value in cpu_info.items():
|
|
print(f" {key}: {value}")
|
|
else:
|
|
print(" Could not retrieve CPU info or lscpu not available.")
|