Merge pull request #368 from mily20001/feature/smartctl

add full smart data from smartctl
This commit is contained in:
Sebastian Hildebrandt 2020-05-12 20:10:14 +02:00 committed by GitHub
commit 2db0a99a98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 131 additions and 35 deletions

View File

@ -382,6 +382,7 @@ I also created a nice little command line tool called [mmon][mmon-github-url] (
| | [0].serialNum | X | | X | X | | serial number | | | [0].serialNum | X | | X | X | | serial number |
| | [0].interfaceType | X | | | X | | SATA, PCIe, ... | | | [0].interfaceType | X | | | X | | SATA, PCIe, ... |
| | [0].smartStatus | X | | X | X | | S.M.A.R.T Status (see Known Issues) | | | [0].smartStatus | X | | X | X | | S.M.A.R.T Status (see Known Issues) |
| | [0].smartData | X | | | | | S.M.A.R.T data from smartctl - requires at least smartmontools 7.0 (see Known Issues) |
| si.blockDevices(cb) | [{...}] | X | | X | X | | returns array of disks, partitions,<br>raids and roms | | si.blockDevices(cb) | [{...}] | X | | X | X | | returns array of disks, partitions,<br>raids and roms |
| | [0].name | X | | X | X | | name | | | [0].name | X | | X | X | | name |
| | [0].type | X | | X | X | | type | | | [0].type | X | | X | X | | type |

View File

@ -739,6 +739,17 @@ function diskLayout(callback) {
let cmd = ''; let cmd = '';
if (_linux) { if (_linux) {
let cmdFullSmart = '';
const commitResult = res => {
for (let i = 0; i < res.length; i++) {
delete res[i].BSDName;
}
if (callback) {
callback(res);
}
resolve(res);
};
exec('export LC_ALL=C; lsblk -ablJO 2>/dev/null; unset LC_ALL', function (error, stdout) { exec('export LC_ALL=C; lsblk -ablJO 2>/dev/null; unset LC_ALL', function (error, stdout) {
if (!error) { if (!error) {
try { try {
@ -789,52 +800,60 @@ function diskLayout(callback) {
smartStatus: 'unknown', smartStatus: 'unknown',
BSDName: BSDName BSDName: BSDName
}); });
cmd = cmd + 'printf "\n' + BSDName + '|"; smartctl -H ' + BSDName + ' | grep overall;'; cmd += `printf "\n${BSDName}|"; smartctl -H ${BSDName} | grep overall;`;
cmdFullSmart += `${cmdFullSmart ? 'printf ",";' : ''}smartctl -a -j ${BSDName};`
}); });
} catch (e) { } catch (e) {
util.noop(); util.noop();
} }
} }
// check S.M.A.R.T. status // check S.M.A.R.T. status
if (cmd) { if (cmdFullSmart) {
cmd = cmd + 'printf "\n"'; exec(cmdFullSmart, function (error, stdout) {
exec(cmd, function (error, stdout) { try {
let lines = stdout.toString().split('\n'); const data = JSON.parse(`[${stdout}]`);
lines.forEach(line => { data.forEach(disk => {
if (line) { const diskBSDName = disk.smartctl.argv[disk.smartctl.argv.length - 1];
let parts = line.split('|');
if (parts.length === 2) { for (let i = 0; i < result.length; i++) {
let BSDName = parts[0]; if (result[i].BSDName === diskBSDName) {
parts[1] = parts[1].trim(); result[i].smartStatus = (disk.smart_status.passed ? 'Ok' : (disk.smart_status.passed === false ? 'Predicted Failure' : 'unknown'));
let parts2 = parts[1].split(':'); result[i].smartData = disk;
if (parts2.length === 2) {
parts2[1] = parts2[1].trim();
let status = parts2[1].toLowerCase();
for (let i = 0; i < result.length; i++) {
if (result[i].BSDName === BSDName) {
result[i].smartStatus = (status === 'passed' ? 'Ok' : (status === 'failed!' ? 'Predicted Failure' : 'unknown'));
}
} }
} }
} });
commitResult(result);
} catch (e) {
if (cmd) {
cmd = cmd + 'printf "\n"';
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
lines.forEach(line => {
if (line) {
let parts = line.split('|');
if (parts.length === 2) {
let BSDName = parts[0];
parts[1] = parts[1].trim();
let parts2 = parts[1].split(':');
if (parts2.length === 2) {
parts2[1] = parts2[1].trim();
let status = parts2[1].toLowerCase();
for (let i = 0; i < result.length; i++) {
if (result[i].BSDName === BSDName) {
result[i].smartStatus = (status === 'passed' ? 'Ok' : (status === 'failed!' ? 'Predicted Failure' : 'unknown'));
}
}
}
}
}
});
commitResult(result);
});
} else {
commitResult(result);
} }
});
for (let i = 0; i < result.length; i++) {
delete result[i].BSDName;
} }
if (callback) {
callback(result);
}
resolve(result);
}); });
} else {
for (let i = 0; i < result.length; i++) {
delete result[i].BSDName;
}
if (callback) {
callback(result);
}
resolve(result);
} }
}); });
} }

76
lib/index.d.ts vendored
View File

@ -123,6 +123,81 @@ export namespace Systeminformation {
voltageMax: number; voltageMax: number;
} }
interface SmartData {
smartctl: {
version: number[];
platform_info: string;
build_info: string;
argv: string[];
exit_status: number;
};
json_format_version: number[];
device: {
name: string;
info_name: string;
type: string;
protocol: string;
}
smart_status: {
passed: boolean;
}
ata_smart_attributes: {
revision: number;
table: {
id: number;
name: string;
value: number;
worst: number;
thresh: number;
when_failed: string;
flags: {
value: number;
string: string;
prefailure: boolean;
updated_online: boolean;
performance: boolean;
error_rate: boolean;
event_count: boolean;
auto_keep: boolean;
};
raw: { value: number; string: string }
}[];
};
power_on_time: {
hours: number;
};
power_cycle_count: number;
temperature: {
current: number;
};
ata_smart_error_log: {
summary: {
revision: number;
count: number;
};
};
ata_smart_self_test_log: {
standard: {
revision: number;
table: {
type: {
value: number;
string: string;
},
status: {
value: number;
string: string;
passed: boolean;
},
lifetime_hours: number;
}[];
count: number;
error_count_total: number;
error_count_outdated: number;
};
}
}
interface DiskLayoutData { interface DiskLayoutData {
device: string; device: string;
type: string; type: string;
@ -140,6 +215,7 @@ export namespace Systeminformation {
serialNum: string; serialNum: string;
interfaceType: string; interfaceType: string;
smartStatus: string; smartStatus: string;
smartData?: SmartData;
} }
interface BatteryData { interface BatteryData {