Warning Firstly, we do not support
Python 2
– the only support provided is forPython 3.9
and greater.
So please ensure you havePython 3.9
or greater installed.
In order to install OCSysInfo
, you can either download the repository manually via GitHub, or via Git.
Then, run the main.py
script located in the project's root. (Do also make sure to install the dependencies as shown below.)
# Clone the repository using Git
git clone https://github.com/KernelWanderers/OCSysInfo.git
# Switch to the repository folder
cd OCSysInfo
# Install dependencies
python3 -m pip install -r requirements.txt
# Run the script
python3 main.py
OCSysInfo takes advantage of each platform's native interaction protocol, except for Linux, which uses a pseudo file system & its distros expose no consistent way of obtaining this information via command/API, in order to extract information about the system's hardware manually.
WMI
Windows's WMI (Windows Management Instrumentation
) is a protocol allowing us to obtain the current system's data—which is practically anything that we could ever ask for. (Some PCI devices even construct the PCIROOT
path where available! Though, generally this data isn't reliable). Data that we look for are as follows (per class):
Win32_Processor
— information about the current system's CPU in use. Though, we only seek out the following properties:
Manufacturer
Name
NumberOfCores
NumberOfLogicalProcessors
Win32_VideoController
— information about the current system's GPU devices in use. The only properties we seek out are Name
(the GPU's friendly name) and PNPDeviceID
, which is basically its PCI path; it includes the device id and vendor id, which we extract.
Win32_NetworkAdapter
— information about [...] system's Network controllers available. We only want the PNPDeviceID
property, from which we can extract the device/vendor id, which we use to query devicehunt.com
and pci-ids.ucw.cz
if nothing was found in devicehunt.com
; the application does not push the device if it cannot be found on either site.
Win32_SoundDevice
— information about [...] system's audio I/O controllers available. As with the network adapter, we only care about PNPDeviceID
.
Win32_BaseBoard
— information about [...] system's motherboard, we only care about the Product
(motherboard model) and Manufacturer
(vendor name) properties.
Win32_Keyboard
— information about [...] system's keyboard(s), their connection types, and possibly their display names. We only look for the Description
(type of connector + display name), and the DeviceID
property.
Win32_PointingDevice
— same as the one item before, but instead for mice/trackpads/touchpads/etc.
sysctl
macOS's sysctl
command exposes a way for us to obtain information about the CPU with ease. The key features of this, which we need, are:
CPU model
CPU instruction flags
Core count
Thread count
Maximum supported SSE version
SSSE3 support
IOKit
Apple's IOKit
framework allows us to interact with the system's devices (we only seek out IOPCIDevice
and IOHDACodecDevice
, as more information would be overtly useless to us.)
We filter by using IOPCIClassMatch
, which can serve as a bit mask match, where the goal is to match the type of device exposed through class-code
(i.e. display controllers will generally have a bit that's equal to 0x03
, multimedia controllers have a bit that's equal to 0x04
, etc.)
With IOPCIDevice
, we're looking for PCI devices which have a specific bit mask, and we obtain the model (if exposed), device ID and vendor ID through there.
With IOHDACodecDevice
, we simply seek out built-in audio controllers that have an HDA codec present. If nothing, that suffices our criteria, is returned, we simply look into 0x04
(bit for PCI multimedia controllers.)
With IODeviceTree
, we're looking for Memory (RAM) modules, which is surprisingly easily obtainable. More-so, we extract the data in the following manner:
Instantiate a list which will hold an N
amount of dictionaries.
Afterwards, loop over each property of the data returned, and convert the values into types we can handle internally (i.e. bytes -> str), and look for the following:
dimm-part-number
— holds a list of each module's part number (yes, each part number is enumerated uniquely for each memory module)
dimm-types
— holds a list of each module's DIMM type (DDR3, DDR4, etc.)
slot-names
— holds a list of each module's BANK
and Channel
location, as well as the index of that specific channel.
dimm-speeds
— holds a list of each module's current frequency (as far as we can tell, there's no way of determining the base clock frequency.)
reg
— holds a byte sequence, from which we determine the capacity of each memory module.
Example: 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
-> [1, 1, 1, 1]
We then multiply each value from the list with 0x010000
(65536
in decimal), and divide the result by 0x10
(16
in decimal) to calculate the capacity. Here, in our aforementioned example, 1 * 0x010000 / 0x10
would be equal to 4096
(0x1000
in hexadecimal), which is, of course 4096MB.
sysfs
Devices enumerated as drm
(/sys/class/drm
) devices are taken into account with the identity of a GPU; which are looked at if cardX
directories are found. The directories of these enumerations will generally contain a cardX/device/device
and cardX/device/vendor
file.
Devices enumerated inside of /sys/class/net
are classified only if they contain a */device/device
and */device/vendor
file (so that we can at least have a strong assumption that it'd be a valid network controller.)
Devices enumerated inside of /sys/class/sound
are looked at for the audio controllers — generally, they'll have a relatively similar enumerations as drm
devices — as a cardX
format.
proc
We are able to take advantage of what is enumerated and the type of data available in Linux's procfs
pseudo filesystem. For example, we may look into /proc/bus/input/devices
to list all the names and paths of each input device, and of course, its location in sysfs
— which is of use for us.
We may also find /proc/cpuinfo
, which holds data about the current system's CPU. Though, generally, thread count isn't explicitly stated as is, but rather, each thread has its own set of data enumerated in cpuinfo
's dump, so we may simply get the thread count by doing: <cpuinfo>.count('processor')
When opening up issues, please list all hardware information relevant, and the issue you're encountering. Show real outputs, and the expected output, etc.
The following contains credits to all the people who helped assist in the making, testing, and polishing of this project. This project would be nothing without them.
@Joshj23 — for extensive help in researching how to discover hardware information on Linux platforms, and providing a big portion of machines used for unit testing.
@Flagers — for general guidance, documentation reference, implementation ideas, general support, documentation, help in fixing the source code's faulty logic, and much, much more.
@vzwGrey — for major assistance in incorporating Rust bindings for Python.
@Acidanthera — for the OpenCore bootloader (its community is what drew inspiration for this project.)
@Rusty-bits — for inspiring the idea of parsing the PCI IDs from the pci.ids list and layout for implementing a search functionality. Though sadly, this idea never reached production; also major thank you to them for suggesting we use Rust for our interops.
@Rvstry — for extensive help in research regarding identifying various devices on Linux platforms, & testing the application in its various stages.
@Dids — for providing the URL to the raw content of the PCI IDs list repository. Though sadly, this was never used, as we turned more towards scraping the site
@DhinakG — for implementing the ioreg
abstraction for OCLP
, and allowing us to copy it over for our own purposes.
@CorpNewt — for implementing the logic of scraping the pci-ids
repository site, and allowing us to use their CLI format.
@Midi1996 — for extensive amounts of assistance in regards to testing the application on different hardware, in the application's various stages.
@ScoobyChan — for guidance and helping with the implementation of Linux's flags detection.
@Quist — for extensive amounts of unit testing on various hardware, they helped immensely with fool-proofing OCSysInfo as best as possible, alongside Joshj23's immense help with unit testing.
@1Revenger1 — for implementing input device detection for Linux platforms, as well as immense assistance for identifying input devices properly on Windows & unit testing.
@Yuichiro — for assistance in testing the application in its various stages.
@Emiyl — for providing extensive assistance with testing the application, and debugging it.
@ThatStella7922 — for extensive amounts of help in regards to testing the application, and debugging it.
@Nemo Xiong — for their implementation of scraping Intel's ARK page
@renegadevi — for extensive amounts of help with fixing the source code's faulty logic.
@mendelsshop — for assistance in testing the application in its various stages, and continuous feedback on new updates/features.
@khronokernel — for extensive amounts of help with fixing the source code's faulty logic, as well as providing extensive amounts of assistance in regards to unit-testing & debugging.
@Fewtarius — for assistance in testing the application in its various stages.
@Apethesis — for assistance in testing the application in its various stages.
@ThatCopy — for assistance in locating and fixing bugs and issues with the terminal on OSX, as well as completely defining and taking care of the logic for detecting ARM (ARM64 and ARMv7) CPUs on Linux.
@Xativive — for assistance in testing the application in its various stages, on various machines.