From 1b7950f0d8dcc1370733d4d558b565df5b184db2 Mon Sep 17 00:00:00 2001 From: Sebastian Hildebrandt Date: Thu, 20 May 2021 17:50:05 +0200 Subject: [PATCH] diskLayout() added smartdata for win (if istalled) --- CHANGELOG.md | 1 + README.md | 3 +- docs/filesystem.html | 6 +-- docs/history.html | 5 ++ docs/index.html | 4 +- lib/filesystem.js | 107 +++++++++++++++++++++++++++---------------- lib/index.d.ts | 58 ++++++++++++++++++----- lib/util.js | 39 ++++++++++++++++ 8 files changed, 166 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f93bac3..68086ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page. | Version | Date | Comment | | -------------- | -------------- | -------- | +| 5.7.0 | 2021-05-20 | `diskLayout()` added smartdata for win (if istalled) | | 5.6.22 | 2021-05-18 | `diskLayout()` fixed to small buffer smartdata (linux) | | 5.6.21 | 2021-05-14 | `graphics()` fixed dual gpu issue (macOS) | | 5.6.20 | 2021-05-07 | `system()` fixed vm detection (linux) | diff --git a/README.md b/README.md index e22ef15..c3f2d50 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ si.cpu() (last 7 major and minor version releases) +- Version 5.7.0: `diskLayout()` added S.M.A.R.T for Windows (if installed) - Version 5.6.0: `cpuTemperature()` added added socket and chipset temp (linux) - Version 5.5.0: `dockerVolumes()` added - Version 5.4.0: `dockerImages()` added @@ -424,7 +425,7 @@ Full function reference with examples can be found at [https://systeminformation | | [0].interfaceType | X | | | X | | SATA, PCIe, ... | | | [0].smartStatus | X | | X | X | | S.M.A.R.T Status (see Known Issues) | | | [0].temperature | X | | | | | S.M.A.R.T temperature | -| | [0].smartData | X | | | | | full S.M.A.R.T data from smartctl
requires at least smartmontools 7.0 | +| | [0].smartData | X | | | X | | full S.M.A.R.T data from smartctl
requires at least smartmontools 7.0 | | si.blockDevices(cb) | [{...}] | X | | X | X | | returns array of disks, partitions,
raids and roms | | | [0].name | X | | X | X | | name | | | [0].type | X | | X | X | | type | diff --git a/docs/filesystem.html b/docs/filesystem.html index 0dea89d..be7ff5f 100644 --- a/docs/filesystem.html +++ b/docs/filesystem.html @@ -252,7 +252,7 @@ X - + X full S.M.A.R.T data from smartctl
requires at least smartmontools 7.0
(see Known Issues) @@ -286,8 +286,8 @@ si.diskLayout().then(data => console.log(data)); smartctl: [Object], device: [Object], model_name: 'SAMSUNG xxxxxxxxxxxx-xxxx', - serial_number: '...serial....', - ... + serial_number: '...serial....', // full structure + ... // see index.d.ts } }, { diff --git a/docs/history.html b/docs/history.html index 9f0562f..eb768fe 100644 --- a/docs/history.html +++ b/docs/history.html @@ -56,6 +56,11 @@ + + 5.7.0 + 2021-05-20 + diskLayout() added smartdata fro Windows (if installed) + 5.6.22 2021-05-18 diff --git a/docs/index.html b/docs/index.html index 4603855..b40657e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -170,7 +170,7 @@
systeminformation
 
-
New Version: 5.6.22
+
New Version: 5.7.0
@@ -211,7 +211,7 @@
Downloads last month
-
413
+
414
Dependents
diff --git a/lib/filesystem.js b/lib/filesystem.js index 9f1a029..b10f255 100755 --- a/lib/filesystem.js +++ b/lib/filesystem.js @@ -13,11 +13,13 @@ // 8. File System // ---------------------------------------------------------------------------------- -const exec = require('child_process').exec; -const execSync = require('child_process').execSync; const util = require('./util'); const fs = require('fs'); +const exec = require('child_process').exec; +const execSync = require('child_process').execSync; +const execPromiseSave = util.promisifySave(require('child_process').exec); + let _platform = process.platform; const _linux = (_platform === 'linux'); @@ -1114,8 +1116,25 @@ function diskLayout(callback) { } if (_windows) { try { - util.wmic('diskdrive get /value').then((stdout) => { - let devices = stdout.toString().split(/\n\s*\n/); + const workload = []; + workload.push(util.wmic('diskdrive get /value')); + workload.push(util.powerShell('Get-PhysicalDisk | Format-List')); + if (util.smartMonToolsInstalled()) { + try { + const smartDev = JSON.parse(execSync('smartctl --scan -j')); + if (smartDev && smartDev.devices && smartDev.devices.length > 0) { + smartDev.devices.forEach((dev) => { + workload.push(execPromiseSave(`smartctl -j -a ${dev.name}`, util.execOptsWin)); + }); + } + } catch (e) { + util.noop(); + } + } + util.promiseAll( + workload + ).then(data => { + let devices = data.results[0].toString().split(/\n\s*\n/); devices.forEach(function (device) { let lines = device.split('\r\n'); const size = util.getValue(lines, 'Size', '=').trim(); @@ -1125,7 +1144,7 @@ function diskLayout(callback) { device: util.getValue(lines, 'PNPDeviceId', '='), type: device.indexOf('SSD') > -1 ? 'SSD' : 'HD', // just a starting point ... better: MSFT_PhysicalDisk - Media Type ... see below name: util.getValue(lines, 'Caption', '='), - vendor: util.getValue(lines, 'Manufacturer', '='), + vendor: getVendorFromModel(util.getValue(lines, 'Caption', '=', true).trim()), size: parseInt(size), bytesPerSector: parseInt(util.getValue(lines, 'BytesPerSector', '=')), totalCylinders: parseInt(util.getValue(lines, 'TotalCylinders', '=')), @@ -1142,43 +1161,51 @@ function diskLayout(callback) { }); } }); - util.powerShell('Get-PhysicalDisk | Format-List') - .then(data => { - let devices = data.split(/\n\s*\n/); - devices.forEach(function (device) { - let lines = device.split('\r\n'); - const serialNum = util.getValue(lines, 'SerialNumber', ':').trim(); - const name = util.getValue(lines, 'FriendlyName', ':').trim().replace('Msft ', 'Microsoft'); - const size = util.getValue(lines, 'Size', ':').trim(); - const model = util.getValue(lines, 'Model', ':').trim(); - const interfaceType = util.getValue(lines, 'BusType', ':').trim(); - let mediaType = util.getValue(lines, 'MediaType', ':').trim(); - if (mediaType === '3' || mediaType === 'HDD') { mediaType = 'HD'; } - if (mediaType === '4') { mediaType = 'SSD'; } - if (mediaType === '5') { mediaType = 'SCM'; } - if (mediaType === 'Unspecified' && (model.toLowerCase().indexOf('virtual') > -1 || model.toLowerCase().indexOf('vbox') > -1)) { mediaType = 'Virtual'; } - if (size) { - let i = util.findObjectByKey(result, 'serialNum', serialNum); - if (i === -1 || serialNum === '') { - i = util.findObjectByKey(result, 'name', name); - } - if (i != -1) { - result[i].type = mediaType; - result[i].interfaceType = interfaceType; - } + devices = data.results[1].split(/\n\s*\n/); + devices.forEach(function (device) { + let lines = device.split('\r\n'); + const serialNum = util.getValue(lines, 'SerialNumber', ':').trim(); + const name = util.getValue(lines, 'FriendlyName', ':').trim().replace('Msft ', 'Microsoft'); + const size = util.getValue(lines, 'Size', ':').trim(); + const model = util.getValue(lines, 'Model', ':').trim(); + const interfaceType = util.getValue(lines, 'BusType', ':').trim(); + let mediaType = util.getValue(lines, 'MediaType', ':').trim(); + if (mediaType === '3' || mediaType === 'HDD') { mediaType = 'HD'; } + if (mediaType === '4') { mediaType = 'SSD'; } + if (mediaType === '5') { mediaType = 'SCM'; } + if (mediaType === 'Unspecified' && (model.toLowerCase().indexOf('virtual') > -1 || model.toLowerCase().indexOf('vbox') > -1)) { mediaType = 'Virtual'; } + if (size) { + let i = util.findObjectByKey(result, 'serialNum', serialNum); + if (i === -1 || serialNum === '') { + i = util.findObjectByKey(result, 'name', name); + } + if (i != -1) { + result[i].type = mediaType; + result[i].interfaceType = interfaceType; + } + } + }); + // S.M.A.R.T + data.results.shift(); + data.results.shift(); + data.results.forEach((smartStr) => { + const smartData = JSON.parse(smartStr); + if (smartData.serial_number) { + const serialNum = smartData.serial_number; + let i = util.findObjectByKey(result, 'serialNum', serialNum); + if (i != -1) { + result[i].smartStatus = (smartData.smart_status.passed ? 'Ok' : (smartData.smart_status.passed === false ? 'Predicted Failure' : 'unknown')); + if (smartData.temperature && smartData.temperature.current) { + result[i].temperature = smartData.temperature.current; } - }); - if (callback) { - callback(result); + result[i].smartData = smartData; } - resolve(result); - }) - .catch(() => { - if (callback) { - callback(result); - } - resolve(result); - }); + } + }); + if (callback) { + callback(result); + } + resolve(result); }); } catch (e) { if (callback) { callback(result); } diff --git a/lib/index.d.ts b/lib/index.d.ts index 30b2530..e72dc39 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -138,6 +138,7 @@ export namespace Systeminformation { } interface SmartData { + json_format_version: number[]; smartctl: { version: number[]; platform_info: string; @@ -145,17 +146,23 @@ export namespace Systeminformation { argv: string[]; exit_status: number; }; - json_format_version: number[]; device: { name: string; info_name: string; type: string; protocol: string; } + model_family?: string, + model_name?: string, + serial_number?: string, + firmware_version?: string, smart_status: { passed: boolean; } - ata_smart_attributes: { + trim?: { + supported: boolean + }, + ata_smart_attributes?: { revision: number; table: { id: number; @@ -177,20 +184,13 @@ export namespace Systeminformation { raw: { value: number; string: string } }[]; }; - power_on_time: { - hours: number; - }; - power_cycle_count: number; - temperature: { - current: number; - }; - ata_smart_error_log: { + ata_smart_error_log?: { summary: { revision: number; count: number; }; }; - ata_smart_self_test_log: { + ata_smart_self_test_log?: { standard: { revision: number; table: { @@ -210,6 +210,42 @@ export namespace Systeminformation { error_count_outdated: number; }; } + nvme_pci_vendor?: { + id: number, + subsystem_id: number + }, + nvme_smart_health_information_log?: { + critical_warning?: number, + temperature?: number, + available_spare?: number, + available_spare_threshold?: number, + percentage_used?: number, + data_units_read?: number, + data_units_written?: number, + host_reads?: number, + host_writes?: number, + controller_busy_time?: number, + power_cycles?: number, + power_on_hours?: number, + unsafe_shutdowns?: number, + media_errors?: number, + num_err_log_entries?: number, + warning_temp_time?: number, + critical_comp_time?: number, + temperature_sensors?: number[] + }, + user_capacity?: { + blocks: number, + bytes: number + }, + logical_block_size?: number, + temperature: { + current: number; + }; + power_cycle_count: number; + power_on_time: { + hours: number; + }; } interface DiskLayoutData { diff --git a/lib/util.js b/lib/util.js index 6b6d5c2..b4c1029 100644 --- a/lib/util.js +++ b/lib/util.js @@ -33,6 +33,7 @@ const _netbsd = (_platform === 'netbsd'); let _cores = 0; let wmicPath = ''; let codepage = ''; +let _smartMonToolsInstalled = null; const WINDIR = process.env.WINDIR || 'C:\\Windows'; @@ -458,6 +459,30 @@ function getCodepage() { } } +function smartMonToolsInstalled() { + if (_smartMonToolsInstalled !== null) { + return _smartMonToolsInstalled; + } + _smartMonToolsInstalled = false; + if (_windows) { + try { + const pathArray = execSync('WHERE smartctl 2>nul', execOptsWin).toString().split('\r\n'); + if (pathArray && pathArray.length) { + _smartMonToolsInstalled = pathArray[0].indexOf(':\\') >= 0; + } else { + _smartMonToolsInstalled = false; + } + } catch (e) { + _smartMonToolsInstalled = false; + } + } + if (_linux || _darwin || _freebsd || _openbsd || _netbsd) { + const pathArray = execSync('which smartctl 2>/dev/null', execOptsWin).toString().split('\r\n'); + _smartMonToolsInstalled = pathArray.length > 0; + } + return _smartMonToolsInstalled; +} + function isRaspberry() { const PI_MODEL_NO = [ 'BCM2708', @@ -931,6 +956,18 @@ function promisify(nodeStyleFunction) { }; } +function promisifySave(nodeStyleFunction) { + return function () { + var args = Array.prototype.slice.call(arguments); + return new Promise(function (resolve) { + args.push(function (err, data) { + resolve(data); + }); + nodeStyleFunction.apply(null, args); + }); + }; +} + function linuxVersion() { let result = ''; if (_linux) { @@ -975,6 +1012,8 @@ exports.isPrototypePolluted = isPrototypePolluted; exports.decodePiCpuinfo = decodePiCpuinfo; exports.promiseAll = promiseAll; exports.promisify = promisify; +exports.promisifySave = promisifySave; +exports.smartMonToolsInstalled = smartMonToolsInstalled; exports.linuxVersion = linuxVersion; exports.stringReplace = stringReplace; exports.stringToLower = stringToLower;