diskLayout() added smartdata for win (if istalled)

This commit is contained in:
Sebastian Hildebrandt 2021-05-20 17:50:05 +02:00
parent c8a9733bcb
commit 1b7950f0d8
8 changed files with 166 additions and 57 deletions

View File

@ -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) |

View File

@ -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<br>requires at least smartmontools 7.0 |
| | [0].smartData | X | | | X | | full S.M.A.R.T data from smartctl<br>requires at least smartmontools 7.0 |
| si.blockDevices(cb) | [{...}] | X | | X | X | | returns array of disks, partitions,<br>raids and roms |
| | [0].name | X | | X | X | | name |
| | [0].type | X | | X | X | | type |

View File

@ -252,7 +252,7 @@
<td>X</td>
<td></td>
<td></td>
<td></td>
<td>X</td>
<td></td>
<td>full S.M.A.R.T data from smartctl<br>requires at least smartmontools 7.0<br>(see Known Issues)</td>
</tr>
@ -286,8 +286,8 @@ si.diskLayout().then(data => console.log(data));</code></pre class="example">
smartctl: [Object],
device: [Object],
model_name: 'SAMSUNG xxxxxxxxxxxx-xxxx',
serial_number: '...serial....',
...
serial_number: '...serial....', // full structure
... // see index.d.ts
}
},
{

View File

@ -56,6 +56,11 @@
</tr>
</thead>
<tbody>
<tr>
<th scope="row">5.7.0</th>
<td>2021-05-20</td>
<td><span class="code">diskLayout()</span> added smartdata fro Windows (if installed)</td>
</tr>
<tr>
<th scope="row">5.6.22</th>
<td>2021-05-18</td>

View File

@ -170,7 +170,7 @@
<img class="logo" src="assets/logo.png">
<div class="title">systeminformation</div>
<div class="subtitle"><span id="typed"></span>&nbsp;</div>
<div class="version">New Version: <span id="version">5.6.22</span></div>
<div class="version">New Version: <span id="version">5.7.0</span></div>
<button class="btn btn-light" onclick="location.href='https://github.com/sebhildebrandt/systeminformation'">View on Github <i class=" fab fa-github"></i></button>
</div>
<div class="down">
@ -211,7 +211,7 @@
<div class="title">Downloads last month</div>
</div>
<div class="col-xl-4 col-lg-4 col-md-4 col-12">
<div class="numbers">413</div>
<div class="numbers">414</div>
<div class="title">Dependents</div>
</div>
</div>

View File

@ -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); }

58
lib/index.d.ts vendored
View File

@ -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 {

View File

@ -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;