versions() fix Command Injection issue (linux), added smartmontools support (macOS)

This commit is contained in:
Sebastian Hildebrandt 2026-02-15 09:00:12 +01:00
parent 612d97e890
commit b67d3715ee
8 changed files with 115 additions and 44 deletions

View File

@ -56,6 +56,7 @@ and adapt your own code to be again compatible to the new version 5.
- `disksIO()` added wait time (linux)
- `diskLayout()`: added USB drives (macOS)
- `diskLayout()`: added S.M.R.R.T. (win)
- `diskLayout()`: added S.M.R.R.T. (macOS)
- `fsSize()`: added available
- `fsSize()`: improved calculation of used
- `getData()`: support for passing parameters and filters (see section General /
@ -90,6 +91,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page.
| Version | Date | Comment |
| ------- | ---------- | --------------------------------------------------------------------------------------------------- |
| 5.31.0 | 2026-02-15 | `diskLayout()` added smartmontools support (macOS) |
| 5.30.8 | 2026-02-14 | `wifiNetworks()` fixed CWE-78 command injection issue (linux) |
| 5.30.7 | 2026-01-31 | `networkInterfaces()` fixed getWindowsIEEE8021x issue (windows) |
| 5.30.6 | 2026-01-22 | `graphics()` improved nvidia-smi detection (windows) |
@ -535,7 +537,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page.
| 4.18.3 | 2020-01-10 | `fsSize()` fix excluding loop/snap devices |
| 4.18.2 | 2020-01-10 | `memLayout()` fix memsize linux (modules >= 32 GB) |
| 4.18.1 | 2020-01-07 | updated docs |
| 4.18.0 | 2020-01-07 | `networkInterfaces()` added dhcp for mac os, added dhcp linux fallback |
| 4.18.0 | 2020-01-07 | `networkInterfaces()` added dhcp for macOS, added dhcp linux fallback |
| 4.17.3 | 2020-01-05 | code cleanup |
| 4.17.2 | 2020-01-05 | `cpu().speed` AMD base frequency and fix (0.00) |
| 4.17.1 | 2020-01-04 | `fsSize()` alpine linux support |

View File

@ -539,8 +539,8 @@ Full function reference with examples can be found at
| | [0].serialNum | X | | X | X | | serial number |
| | [0].interfaceType | X | | 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 | | | X | | full S.M.A.R.T data from smartctl<br>requires at least smartmontools 7.0 |
| | [0].temperature | X | | X | X | | S.M.A.R.T temperature |
| | [0].smartData | X | | 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

@ -242,8 +242,8 @@
<td>[0].temperature</td>
<td>X</td>
<td></td>
<td></td>
<td></td>
<td>X</td>
<td>X</td>
<td></td>
<td>S.M.A.R.T temperature (if available)</td>
</tr>
@ -252,7 +252,7 @@
<td>[0].smartData</td>
<td>X</td>
<td></td>
<td></td>
<td>X</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>

View File

@ -57,6 +57,12 @@
</tr>
</thead>
<tbody>
<tr>
<th scope="row">5.31.0
</th>
<td>2026-02-15</td>
<td><span class="code">diskLayout()</span> added smartmontools support (macOS)</td>
</tr>
<tr>
<th scope="row">5.30.8
</th>

View File

@ -170,7 +170,7 @@
<img class="logo" src="assets/logo.png" alt="logo">
<div class="title">systeminformation</div>
<div class="subtitle"><span id="typed"></span>&nbsp;</div>
<div class="version">New Version: <span id="version">5.30.8</span></div>
<div class="version">New Version: <span id="version">5.31.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">
@ -212,7 +212,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">969</div>
<div class="numbers">973</div>
<div class="title">Dependents</div>
</div>
</div>

View File

@ -73,10 +73,14 @@
<p><span class="code">node.js</span> and <span class="code">get-WmiObject</span> are not able to determine correct CPU current speed on windows and macOS.
This means, you will have constant values here on both platforms for all processor cores in <span class="code">cpuCurrentSpeed()</span>.</p>
<h4>Linux S.M.A.R.T. Status</h4>
<h4>Linux, Windows, macOS - S.M.A.R.T. Status</h4>
<p>To be able to detect S.M.A.R.T. status on Linux you need to install <span class="code">smartmontools</span>. On DEBIAN based linux distributions you can install it by running:</p>
<p>To be able to detect S.M.A.R.T. status on macOS, Windows and Linux you need to install <span class="code">smartmontools</span>.</p>
<p>On DEBIAN based linux distributions you can install it by running:</p>
<pre>$ sudo apt-get install smartmontools</pre>
<p>On macOS you can install it using <span class="code">brew</span>:</p>
<pre>$ brew install smartmontools</pre>
<p>On windows you can download it from <a href="https://www.smartmontools.org/">https://www.smartmontools.org/</a></p>
<p>If you have smartmontools version >= 7.0 then you will get also full smart data in diskLayout()</p>
<h4>Stats Functions</h4>

View File

@ -1349,6 +1349,7 @@ function diskLayout(callback) {
resolve(result);
}
if (_darwin) {
let cmdFullSmart = '';
exec('system_profiler SPSerialATADataType SPNVMeDataType SPUSBDataType', { maxBuffer: 1024 * 1024 }, (error, stdout) => {
if (!error) {
// split by type:
@ -1420,6 +1421,7 @@ function diskLayout(callback) {
BSDName: BSDName
});
cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
cmdFullSmart += `${cmdFullSmart ? 'printf ",";' : ''}smartctl -a -j ${BSDName};`;
}
}
});
@ -1475,6 +1477,7 @@ function diskLayout(callback) {
BSDName: BSDName
});
cmd = `${cmd}printf "\n${BSDName}|"; diskutil info /dev/${BSDName} | grep SMART;`;
cmdFullSmart += `${cmdFullSmart ? 'printf ",";' : ''}smartctl -a -j ${BSDName};`;
}
}
});
@ -1527,13 +1530,64 @@ function diskLayout(callback) {
BSDName: BSDName
});
cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
cmdFullSmart += `${cmdFullSmart ? 'printf ",";' : ''}smartctl -a -j ${BSDName};`;
}
}
});
} catch {
util.noop();
}
// check S.M.A.R.T. status
if (cmdFullSmart) {
exec(cmdFullSmart, { maxBuffer: 1024 * 1024 }, (error, stdout) => {
try {
const data = JSON.parse(`[${stdout}]`);
data.forEach((disk) => {
const diskBSDName = disk.smartctl.argv[disk.smartctl.argv.length - 1];
for (let i = 0; i < result.length; i++) {
if (result[i].BSDName === diskBSDName) {
result[i].smartStatus = disk.smart_status.passed ? 'Ok' : disk.smart_status.passed === false ? 'Predicted Failure' : 'unknown';
if (disk.temperature && disk.temperature.current) {
result[i].temperature = disk.temperature.current;
}
result[i].smartData = disk;
}
}
});
commitResult(result);
} catch (e) {
if (cmd) {
cmd = cmd + 'printf "\n"';
exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => {
const lines = stdout.toString().split('\n');
lines.forEach((line) => {
if (line) {
const parts = line.split('|');
if (parts.length === 2) {
const BSDName = parts[0];
parts[1] = parts[1].trim();
const parts2 = parts[1].split(':');
if (parts2.length === 2) {
parts2[1] = parts2[1].trim();
const 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);
}
}
});
} else if (cmd) {
cmd = cmd + 'printf "\n"';
exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => {
const lines = stdout.toString().split('\n');

View File

@ -769,9 +769,14 @@ function versions(apps, callback) {
if (_linux) {
exec('locate bin/postgres', (error, stdout) => {
if (!error) {
const postgresqlBin = stdout.toString().split('\n').sort();
const safePath = /^[a-zA-Z0-9/_.-]+$/;
const postgresqlBin = stdout
.toString()
.split('\n')
.filter((p) => safePath.test(p.trim()))
.sort();
if (postgresqlBin.length) {
exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', (error, stdout) => {
execFile(postgresqlBin[postgresqlBin.length - 1], ['-V'], (error, stdout) => {
if (!error) {
const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';