diff --git a/README.md b/README.md
index 7c9943d..27b668c 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ This is amazing. Started as a small project just for myself, it now has > 10,000
## Upcoming
-**MacOS on ARM (Apple silicon support), Windows on ARM**: November 11th 2020 - We will have a closer look on that! I just ordered new hardware (any support is highly appreciated - [Buy me a coffe](https://www.buymeacoffee.com/systeminfo)). As soon as I have the new hardware here, I work very hard on it to get full native support for those platforms!
+**MacOS on ARM (Apple silicon support), Windows on ARM**: November 11th 2020 - We will have a closer look on that! I just ordered new hardware (any support is highly appreciated - [Buy me a coffee](https://www.buymeacoffee.com/systeminfo)). As soon as I have the new hardware here, I work very hard on it to get full native support for those platforms!
**Version 5**: we are planning a new major version with some minor breaking changes and some additional features. Will try to make this available Q1 of 2021.
diff --git a/docs/security.html b/docs/security.html
index 387e83d..3e4d649 100644
--- a/docs/security.html
+++ b/docs/security.html
@@ -46,7 +46,7 @@
Affected versions:
< 4.31.1
Date: 2020-12-11
- CVE indentifier CVE-2020-28448
+ CVE indentifier CVE-2020-26274, CVE-2020-28448
Impact
diff --git a/lib/graphics.js b/lib/graphics.js
index c1f0a6c..566e6c8 100644
--- a/lib/graphics.js
+++ b/lib/graphics.js
@@ -14,11 +14,13 @@
// ----------------------------------------------------------------------------------
const os = require('os');
+const fs = require('fs');
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const util = require('./util');
let _platform = process.platform;
+let _nvidiaSmiPath = '';
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
@@ -204,7 +206,8 @@ function graphics(callback) {
bus: '',
busAddress: '',
vram: -1,
- vramDynamic: false
+ vramDynamic: false,
+ pciID: ''
};
let isGraphicsController = false;
// PCI bus IDs
@@ -238,9 +241,14 @@ function graphics(callback) {
bus: '',
busAddress: '',
vram: -1,
- vramDynamic: false
+ vramDynamic: false,
};
}
+
+ const pciIDCandidate = lines[i].split(' ')[0];
+ if (/[\da-fA-F]{2}:[\da-fA-F]{2}\.[\da-fA-F]/.test(pciIDCandidate)) {
+ currentController.busAddress = pciIDCandidate;
+ }
isGraphicsController = true;
let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
@@ -310,7 +318,7 @@ function graphics(callback) {
return devices
}, {});
for (let deviceId in devices) {
- const device = devices[deviceId]
+ const device = devices[deviceId];
if (device['CL_DEVICE_TYPE'] === 'CL_DEVICE_TYPE_GPU') {
let busAddress;
if (device['CL_DEVICE_TOPOLOGY_AMD']) {
@@ -354,9 +362,114 @@ function graphics(callback) {
}
}
}
- return controllers
+ return controllers;
}
+ function getNvidiaSmi() {
+ if (_nvidiaSmiPath) {
+ return _nvidiaSmiPath;
+ }
+
+ if (_windows) {
+ try {
+ const basePath = util.WINDIR + '\\System32\\DriverStore\\FileRepository';
+ const dirContent = fs.readdirSync(basePath);
+ const candidateDirs = dirContent.filter(dir => dir.startsWith('nv'));
+ const targetDir = candidateDirs.find(dir => {
+ const content = fs.readdirSync([basePath, dir].join('/'));
+ return content.includes('nvidia-smi.exe');
+ });
+
+ if (targetDir) {
+ _nvidiaSmiPath = [basePath, targetDir, 'nvidia-smi.exe'].join('/');
+ }
+ } catch (e) {
+ util.noop()
+ }
+ } else if (_linux) {
+ _nvidiaSmiPath = 'nvidia-smi';
+ }
+ return _nvidiaSmiPath;
+ }
+
+ function nvidiaSmi(options) {
+ const nvidiaSmiExe = getNvidiaSmi();
+ if (nvidiaSmiExe) {
+ const nvidiaSmiOpts = '--query-gpu=driver_version,pci.sub_device_id,name,pci.bus_id,fan.speed,memory.total,memory.used,memory.free,utilization.gpu,utilization.memory,temperature.gpu,temperature.memory,power.draw,power.limit,clocks.gr,clocks.mem --format=csv,noheader,nounits'
+ try {
+ const res = execSync(nvidiaSmiExe + ' ' + nvidiaSmiOpts, options);
+ return res;
+ } catch (e) {
+ util.noop();
+ }
+ }
+ return '';
+ }
+
+ function nvidiaDevices() {
+
+ function safeParseNumber(value) {
+ if ([null, undefined].includes(value)) {
+ return value;
+ }
+ return parseFloat(value);
+ }
+
+ const stdout = nvidiaSmi();
+ if (!stdout) {
+ return [];
+ }
+
+ const gpus = stdout.split('\n').filter(Boolean);
+ const results = gpus.map(gpu => {
+ const splittedData = gpu.split(', ').map(value => value.includes('N/A') ? undefined : value);
+ if (splittedData.length === 16) {
+ return {
+ driverVersion: splittedData[0],
+ subDeviceId: splittedData[1],
+ name: splittedData[2],
+ pciBus: splittedData[3],
+ fanSpeed: safeParseNumber(splittedData[4]),
+ memoryTotal: safeParseNumber(splittedData[5]),
+ memoryUsed: safeParseNumber(splittedData[6]),
+ memoryFree: safeParseNumber(splittedData[7]),
+ utilizationGpu: safeParseNumber(splittedData[8]),
+ utilizationMemory: safeParseNumber(splittedData[9]),
+ temperatureGpu: safeParseNumber(splittedData[10]),
+ temperatureMemory: safeParseNumber(splittedData[11]),
+ powerDraw: safeParseNumber(splittedData[12]),
+ powerLimit: safeParseNumber(splittedData[13]),
+ clockCore: safeParseNumber(splittedData[14]),
+ clockMemory: safeParseNumber(splittedData[15]),
+ }
+ }
+ });
+
+ return results;
+ }
+
+ function mergeControllerNvidia(controller, nvidia) {
+ if (nvidia.driverVersion) { controller.driverVersion = nvidia.driverVersion; }
+ if (nvidia.subDeviceId) { controller.subDeviceId = nvidia.subDeviceId; }
+ if (nvidia.name) { controller.name = nvidia.name; }
+ if (nvidia.pciBus) { controller.pciBus = nvidia.pciBus; }
+ if (nvidia.fanSpeed) { controller.fanSpeed = nvidia.fanSpeed; }
+ if (nvidia.memoryTotal) { controller.memoryTotal = nvidia.memoryTotal; }
+ if (nvidia.memoryUsed) { controller.memoryUsed = nvidia.memoryUsed; }
+ if (nvidia.memoryFree) { controller.memoryFree = nvidia.memoryFree; }
+ if (nvidia.utilizationGpu) { controller.utilizationGpu = nvidia.utilizationGpu; }
+ if (nvidia.utilizationMemory) { controller.utilizationMemory = nvidia.utilizationMemory; }
+ if (nvidia.temperatureGpu) { controller.temperatureGpu = nvidia.temperatureGpu; }
+ if (nvidia.temperatureMemory) { controller.temperatureMemory = nvidia.temperatureMemory; }
+ if (nvidia.powerDraw) { controller.powerDraw = nvidia.powerDraw; }
+ if (nvidia.powerLimit) { controller.powerLimit = nvidia.powerLimit; }
+ if (nvidia.clockCore) { controller.clockCore = nvidia.clockCore; }
+ if (nvidia.clockMemory) { controller.clockMemory = nvidia.clockMemory; }
+ return controller
+ }
+
+
+
function parseLinesLinuxEdid(edid) {
// parsen EDID
// --> model
@@ -592,6 +705,11 @@ function graphics(callback) {
if (!error) {
let lines = stdout.toString().split('\n');
result.controllers = parseLinesLinuxControllers(lines);
+ const nvidiaData = nvidiaDevices();
+ // needs to be rewritten ... using no spread operators
+ result.controllers = result.controllers.map(( controller ) => { // match by busAddress
+ return mergeControllerNvidia(controller, nvidiaData.find(({ pciBus }) => pciBus.endsWith(controller.busAddress)) || {} );
+ })
}
let cmd = "clinfo --raw";
exec(cmd, function (error, stdout) {
@@ -643,13 +761,18 @@ function graphics(callback) {
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
workload.push(util.powerShell('gwmi WmiMonitorID -Namespace root\\wmi | ForEach-Object {(($_.ManufacturerName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.ProductCodeID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.UserFriendlyName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.SerialNumberID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + $_.InstanceName}'));
+ const nvidiaData = nvidiaDevices();
+
Promise.all(
workload
).then(data => {
// controller
let csections = data[0].split(/\n\s*\n/);
result.controllers = parseLinesWindowsControllers(csections);
-
+ // needs to be rewritten ... using no spread operators
+ result.controllers = result.controllers.map((controller) => { // match by subDeviceId
+ return mergeControllerNvidia(controller, nvidiaData.find(device => controller.subDeviceId.toLowerCase() === device.subDeviceId.split('x')[1].toLowerCase()) || {});
+ })
// displays
let dsections = data[1].split(/\n\s*\n/);
// result.displays = parseLinesWindowsDisplays(dsections);
@@ -732,12 +855,17 @@ function graphics(callback) {
if (sections[i].trim() !== '') {
let lines = sections[i].trim().split('\r\n');
+ let subDeviceId = util.getValue(lines, 'PNPDeviceID', '=').match(/SUBSYS_[a-fA-F\d]{8}/)[0];
+ if (subDeviceId) {
+ subDeviceId = subDeviceId.split('_')[1];
+ }
controllers.push({
vendor: util.getValue(lines, 'AdapterCompatibility', '='),
model: util.getValue(lines, 'name', '='),
bus: util.getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
vram: parseInt(util.getValue(lines, 'AdapterRAM', '='), 10) / 1024 / 1024,
- vramDynamic: (util.getValue(lines, 'VideoMemoryType', '=') === '2')
+ vramDynamic: (util.getValue(lines, 'VideoMemoryType', '=') === '2'),
+ subDeviceId
});
_resolutionx = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', '=')) || _resolutionx;
_resolutiony = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', '=')) || _resolutiony;
@@ -749,30 +877,6 @@ function graphics(callback) {
return controllers;
}
- // function parseLinesWindowsDisplays(sections) {
- // let displays = [];
- // for (let i in sections) {
- // if (sections.hasOwnProperty(i)) {
- // if (sections[i].trim() !== '') {
- // let lines = sections[i].trim().split('\r\n');
- // displays.push({
- // vendor: util.getValue(lines, 'MonitorManufacturer', '='),
- // model: util.getValue(lines, 'Name', '='),
- // main: false,
- // builtin: false,
- // connection: '',
- // sizex: -1,
- // sizey: -1,
- // pixeldepth: -1,
- // resolutionx: util.toInt(util.getValue(lines, 'ScreenWidth', '=')),
- // resolutiony: util.toInt(util.getValue(lines, 'ScreenHeight', '=')),
- // });
- // }
- // }
- // }
- // return displays;
- // }
-
function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections) {
let displays = [];
let vendor = '';
diff --git a/lib/index.d.ts b/lib/index.d.ts
index 76cb327..8179aec 100644
--- a/lib/index.d.ts
+++ b/lib/index.d.ts
@@ -255,6 +255,7 @@ export namespace Systeminformation {
busAddress?: string;
vram: number;
vramDynamic: boolean;
+ subDeviceId?: string;
}
interface GraphicsDisplayData {
diff --git a/lib/util.js b/lib/util.js
index 1931a88..3a9b51f 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -830,3 +830,4 @@ exports.stringToLower = stringToLower;
exports.stringToString = stringToString;
exports.stringSubstr = stringSubstr;
exports.stringTrim = stringTrim;
+exports.WINDIR = WINDIR;