From c52f9fd07fef42d2d8e8c66f75b42178da701c68 Mon Sep 17 00:00:00 2001 From: Sebastian Hildebrandt Date: Tue, 16 Dec 2025 07:18:20 +0100 Subject: [PATCH] fsSize() fix drive sanitation (windows) --- CHANGELOG.md | 1 + docs/history.html | 5 + docs/index.html | 4 +- docs/security.html | 15 + lib/filesystem.js | 833 +++++++++++++++++++++++++++------------------ lib/util.js | 421 +++++++++++++---------- 6 files changed, 767 insertions(+), 512 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf20c81..6a75090 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page. | Version | Date | Comment | | ------- | ---------- | --------------------------------------------------------------------------------------------------- | +| 5.27.14 | 2025-12-15 | `fsSize()` fix drive sanitation (windows) | | 5.27.13 | 2025-12-10 | `cpuCurrentSpeed()` fix hasOwnProperty | | 5.27.12 | 2025-12-09 | `networkConnections()` fix pid issue (macOS) | | 5.27.11 | 2025-10-05 | `system()` added latest mac studio versions (macOS) | diff --git a/docs/history.html b/docs/history.html index 3951f6b..670f862 100644 --- a/docs/history.html +++ b/docs/history.html @@ -57,6 +57,11 @@ + + 5.27.14 + 2025-12-16 + fsSize() fix sanitation drive (windows) + 5.27.13 2025-12-10 diff --git a/docs/index.html b/docs/index.html index 45dccd5..c85c704 100644 --- a/docs/index.html +++ b/docs/index.html @@ -166,11 +166,11 @@
- Security advisory:
Update to v5.23.7
+ Security advisory:
Update to v5.27.14
systeminformation
 
-
New Version: 5.27.13
+
New Version: 5.27.14
diff --git a/docs/security.html b/docs/security.html index 3aa25c0..6964f26 100644 --- a/docs/security.html +++ b/docs/security.html @@ -44,6 +44,21 @@
Security Advisories
+

fsSize Command Injection Vulnerability

+

Affected versions: + < 5.23.14
+ Date: 2025-12-16
+ CVE indentifier CVE-??? +

+ +

Impact

+

We had an issue that there was a possibility to perform a potential command injection possibility by manipulating Win32_logicaldisk input in fsSize() on windows machines.

+ +

Patch

+

Problem was fixed with parameter checking. If you are using version 5, please upgrade to version >= 5.27.14.

+
+
+

SSID Command Injection Vulnerability

Affected versions: < 5.23.7
diff --git a/lib/filesystem.js b/lib/filesystem.js index cbc90c9..c293e29 100644 --- a/lib/filesystem.js +++ b/lib/filesystem.js @@ -20,24 +20,23 @@ 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 _platform = process.platform; -const _linux = (_platform === 'linux' || _platform === 'android'); -const _darwin = (_platform === 'darwin'); -const _windows = (_platform === 'win32'); -const _freebsd = (_platform === 'freebsd'); -const _openbsd = (_platform === 'openbsd'); -const _netbsd = (_platform === 'netbsd'); -const _sunos = (_platform === 'sunos'); +const _linux = _platform === 'linux' || _platform === 'android'; +const _darwin = _platform === 'darwin'; +const _windows = _platform === 'win32'; +const _freebsd = _platform === 'freebsd'; +const _openbsd = _platform === 'openbsd'; +const _netbsd = _platform === 'netbsd'; +const _sunos = _platform === 'sunos'; -let _fs_speed = {}; -let _disk_io = {}; +const _fs_speed = {}; +const _disk_io = {}; // -------------------------- // FS - mounted file systems function fsSize(drive, callback) { - if (util.isFunction(drive)) { callback = drive; drive = ''; @@ -47,30 +46,36 @@ function fsSize(drive, callback) { let osMounts = []; function getmacOsFsType(fs) { - if (!fs.startsWith('/')) { return 'NFS'; } + if (!fs.startsWith('/')) { + return 'NFS'; + } const parts = fs.split('/'); const fsShort = parts[parts.length - 1]; - const macOsDisksSingle = macOsDisks.filter(item => item.indexOf(fsShort) >= 0); - if (macOsDisksSingle.length === 1 && macOsDisksSingle[0].indexOf('APFS') >= 0) { return 'APFS'; } + const macOsDisksSingle = macOsDisks.filter((item) => item.indexOf(fsShort) >= 0); + if (macOsDisksSingle.length === 1 && macOsDisksSingle[0].indexOf('APFS') >= 0) { + return 'APFS'; + } return 'HFS'; } function isLinuxTmpFs(fs) { const linuxTmpFileSystems = ['rootfs', 'unionfs', 'squashfs', 'cramfs', 'initrd', 'initramfs', 'devtmpfs', 'tmpfs', 'udev', 'devfs', 'specfs', 'type', 'appimaged']; let result = false; - linuxTmpFileSystems.forEach(linuxFs => { - if (fs.toLowerCase().indexOf(linuxFs) >= 0) { result = true; } + linuxTmpFileSystems.forEach((linuxFs) => { + if (fs.toLowerCase().indexOf(linuxFs) >= 0) { + result = true; + } }); return result; } function filterLines(stdout) { - let lines = stdout.toString().split('\n'); + const lines = stdout.toString().split('\n'); lines.shift(); if (stdout.toString().toLowerCase().indexOf('filesystem')) { let removeLines = 0; for (let i = 0; i < lines.length; i++) { - if (lines[i] && lines[i].toLowerCase().startsWith('filesystem')) { + if (lines[i]?.toLowerCase().startsWith('filesystem')) { removeLines = i; } } @@ -82,21 +87,21 @@ function fsSize(drive, callback) { } function parseDf(lines) { - let data = []; - lines.forEach(function (line) { + const data = []; + lines.forEach((line) => { if (line !== '') { line = line.replace(/ +/g, ' ').split(' '); - if (line && ((line[0].startsWith('/')) || (line[6] && line[6] === '/') || (line[0].indexOf('/') > 0) || (line[0].indexOf(':') === 1) || !_darwin && !isLinuxTmpFs(line[1]))) { + if (line && (line[0].startsWith('/') || (line[6] && line[6] === '/') || line[0].indexOf('/') > 0 || line[0].indexOf(':') === 1 || (!_darwin && !isLinuxTmpFs(line[1])))) { const fs = line[0]; - const fsType = ((_linux || _freebsd || _openbsd || _netbsd) ? line[1] : getmacOsFsType(line[0])); - const size = parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[2] : line[1])) * 1024; - const used = parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[3] : line[2])) * 1024; - const available = parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[4] : line[3])) * 1024; + const fsType = _linux || _freebsd || _openbsd || _netbsd ? line[1] : getmacOsFsType(line[0]); + const size = parseInt(_linux || _freebsd || _openbsd || _netbsd ? line[2] : line[1], 10) * 1024; + const used = parseInt(_linux || _freebsd || _openbsd || _netbsd ? line[3] : line[2], 10) * 1024; + const available = parseInt(_linux || _freebsd || _openbsd || _netbsd ? line[4] : line[3], 10) * 1024; const use = parseFloat((100.0 * (used / (used + available))).toFixed(2)); - let rw = osMounts && Object.keys(osMounts).length > 0 ? osMounts[fs] || false : null; - line.splice(0, (_linux || _freebsd || _openbsd || _netbsd) ? 6 : 5); + const rw = osMounts && Object.keys(osMounts).length > 0 ? osMounts[fs] || false : null; + line.splice(0, _linux || _freebsd || _openbsd || _netbsd ? 6 : 5); const mount = line.join(' '); - if (!data.find(el => (el.fs === fs && el.type === fsType))) { + if (!data.find((el) => el.fs === fs && el.type === fsType)) { data.push({ fs, type: fsType, @@ -124,48 +129,62 @@ function fsSize(drive, callback) { if (_darwin) { cmd = 'df -kP'; try { - macOsDisks = execSync('diskutil list').toString().split('\n').filter(line => { - return !line.startsWith('/') && line.indexOf(':') > 0; - }); - execSync('mount').toString().split('\n').filter(line => { - return line.startsWith('/'); - }).forEach((line) => { - osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1; - }); - } catch (e) { + macOsDisks = execSync('diskutil list') + .toString() + .split('\n') + .filter((line) => { + return !line.startsWith('/') && line.indexOf(':') > 0; + }); + execSync('mount') + .toString() + .split('\n') + .filter((line) => { + return line.startsWith('/'); + }) + .forEach((line) => { + osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1; + }); + } catch { util.noop(); } } if (_linux) { try { cmd = 'export LC_ALL=C; df -lkPTx squashfs; unset LC_ALL'; - execSync('cat /proc/mounts 2>/dev/null', util.execOptsLinux).toString().split('\n').filter(line => { - return line.startsWith('/'); - }).forEach((line) => { - osMounts[line.split(' ')[0]] = osMounts[line.split(' ')[0]] || false; - if (line.toLowerCase().indexOf('/snap/') === -1) { - osMounts[line.split(' ')[0]] = ((line.toLowerCase().indexOf('rw,') >= 0 || line.toLowerCase().indexOf(' rw ') >= 0)); - } - }); - } catch (e) { + execSync('cat /proc/mounts 2>/dev/null', util.execOptsLinux) + .toString() + .split('\n') + .filter((line) => { + return line.startsWith('/'); + }) + .forEach((line) => { + osMounts[line.split(' ')[0]] = osMounts[line.split(' ')[0]] || false; + if (line.toLowerCase().indexOf('/snap/') === -1) { + osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('rw,') >= 0 || line.toLowerCase().indexOf(' rw ') >= 0; + } + }); + } catch { util.noop(); } } if (_freebsd || _openbsd || _netbsd) { try { cmd = 'df -lkPT'; - execSync('mount').toString().split('\n').forEach((line) => { - osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1; - }); - } catch (e) { + execSync('mount') + .toString() + .split('\n') + .forEach((line) => { + osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1; + }); + } catch { util.noop(); } } - exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) { - let lines = filterLines(stdout); + exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => { + const lines = filterLines(stdout); data = parseDf(lines); if (drive) { - data = data.filter(item => { + data = data.filter((item) => { return item.fs.toLowerCase().indexOf(drive.toLowerCase()) >= 0 || item.mount.toLowerCase().indexOf(drive.toLowerCase()) >= 0; }); } @@ -175,9 +194,9 @@ function fsSize(drive, callback) { } resolve(data); } else { - exec('df -kPT', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + exec('df -kPT', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = filterLines(stdout); + const lines = filterLines(stdout); data = parseDf(lines); } if (callback) { @@ -189,22 +208,25 @@ function fsSize(drive, callback) { }); } if (_sunos) { - if (callback) { callback(data); } + if (callback) { + callback(data); + } resolve(data); } if (_windows) { try { - const cmd = `Get-WmiObject Win32_logicaldisk | select Access,Caption,FileSystem,FreeSpace,Size ${drive ? '| where -property Caption -eq ' + drive : ''} | fl`; + const driveSanitized = drive ? util.sanitizeShellString(drive, true) : ''; + const cmd = `Get-WmiObject Win32_logicaldisk | select Access,Caption,FileSystem,FreeSpace,Size ${driveSanitized ? '| where -property Caption -eq ' + driveSanitized : ''} | fl`; util.powerShell(cmd).then((stdout, error) => { if (!error) { - let devices = stdout.toString().split(/\n\s*\n/); - devices.forEach(function (device) { - let lines = device.split('\r\n'); + const devices = stdout.toString().split(/\n\s*\n/); + devices.forEach((device) => { + const lines = device.split('\r\n'); const size = util.toInt(util.getValue(lines, 'size', ':')); const free = util.toInt(util.getValue(lines, 'freespace', ':')); const caption = util.getValue(lines, 'caption', ':'); const rwValue = util.getValue(lines, 'access', ':'); - const rw = rwValue ? (util.toInt(rwValue) !== 1) : null; + const rw = rwValue ? util.toInt(rwValue) !== 1 : null; if (size) { data.push({ fs: caption, @@ -224,8 +246,10 @@ function fsSize(drive, callback) { } resolve(data); }); - } catch (e) { - if (callback) { callback(data); } + } catch { + if (callback) { + callback(data); + } resolve(data); } } @@ -239,7 +263,6 @@ exports.fsSize = fsSize; // FS - open files count function fsOpenFiles(callback) { - return new Promise((resolve) => { process.nextTick(() => { const result = { @@ -248,10 +271,10 @@ function fsOpenFiles(callback) { available: null }; if (_freebsd || _openbsd || _netbsd || _darwin) { - let cmd = 'sysctl -i kern.maxfiles kern.num_files kern.open_files'; - exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) { + const cmd = 'sysctl -i kern.maxfiles kern.num_files kern.open_files'; + exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = stdout.toString().split('\n'); + const lines = stdout.toString().split('\n'); result.max = parseInt(util.getValue(lines, 'kern.maxfiles', ':'), 10); result.allocated = parseInt(util.getValue(lines, 'kern.num_files', ':'), 10) || parseInt(util.getValue(lines, 'kern.open_files', ':'), 10); result.available = result.max - result.allocated; @@ -263,16 +286,18 @@ function fsOpenFiles(callback) { }); } if (_linux) { - fs.readFile('/proc/sys/fs/file-nr', function (error, stdout) { + fs.readFile('/proc/sys/fs/file-nr', (error, stdout) => { if (!error) { - let lines = stdout.toString().split('\n'); + const lines = stdout.toString().split('\n'); if (lines[0]) { const parts = lines[0].replace(/\s+/g, ' ').split(' '); if (parts.length === 3) { result.allocated = parseInt(parts[0], 10); result.available = parseInt(parts[1], 10); result.max = parseInt(parts[2], 10); - if (!result.available) { result.available = result.max - result.allocated; } + if (!result.available) { + result.available = result.max - result.allocated; + } } } if (callback) { @@ -280,9 +305,9 @@ function fsOpenFiles(callback) { } resolve(result); } else { - fs.readFile('/proc/sys/fs/file-max', function (error, stdout) { + fs.readFile('/proc/sys/fs/file-max', (error, stdout) => { if (!error) { - let lines = stdout.toString().split('\n'); + const lines = stdout.toString().split('\n'); if (lines[0]) { result.max = parseInt(lines[0], 10); } @@ -296,11 +321,15 @@ function fsOpenFiles(callback) { }); } if (_sunos) { - if (callback) { callback(null); } + if (callback) { + callback(null); + } resolve(null); } if (_windows) { - if (callback) { callback(null); } + if (callback) { + callback(null); + } resolve(null); } }); @@ -313,18 +342,18 @@ exports.fsOpenFiles = fsOpenFiles; // disks function parseBytes(s) { - return parseInt(s.substr(s.indexOf(' (') + 2, s.indexOf(' Bytes)') - 10)); + return parseInt(s.substr(s.indexOf(' (') + 2, s.indexOf(' Bytes)') - 10), 10); } function parseDevices(lines) { - let devices = []; + const devices = []; let i = 0; - lines.forEach(line => { + lines.forEach((line) => { if (line.length > 0) { if (line[0] === '*') { i++; } else { - let parts = line.split(':'); + const parts = line.split(':'); if (parts.length > 1) { if (!devices[i]) { devices[i] = { @@ -347,22 +376,50 @@ function parseDevices(lines) { } parts[0] = parts[0].trim().toUpperCase().replace(/ +/g, ''); parts[1] = parts[1].trim(); - if ('DEVICEIDENTIFIER' === parts[0]) { devices[i].identifier = parts[1]; } - if ('DEVICENODE' === parts[0]) { devices[i].name = parts[1]; } - if ('VOLUMENAME' === parts[0]) { - if (parts[1].indexOf('Not applicable') === -1) { devices[i].label = parts[1]; } + if ('DEVICEIDENTIFIER' === parts[0]) { + devices[i].identifier = parts[1]; + } + if ('DEVICENODE' === parts[0]) { + devices[i].name = parts[1]; + } + if ('VOLUMENAME' === parts[0]) { + if (parts[1].indexOf('Not applicable') === -1) { + devices[i].label = parts[1]; + } + } + if ('PROTOCOL' === parts[0]) { + devices[i].protocol = parts[1]; + } + if ('DISKSIZE' === parts[0]) { + devices[i].size = parseBytes(parts[1]); + } + if ('FILESYSTEMPERSONALITY' === parts[0]) { + devices[i].fsType = parts[1]; + } + if ('MOUNTPOINT' === parts[0]) { + devices[i].mount = parts[1]; + } + if ('VOLUMEUUID' === parts[0]) { + devices[i].uuid = parts[1]; + } + if ('READ-ONLYMEDIA' === parts[0] && parts[1] === 'Yes') { + devices[i].physical = 'CD/DVD'; + } + if ('SOLIDSTATE' === parts[0] && parts[1] === 'Yes') { + devices[i].physical = 'SSD'; + } + if ('VIRTUAL' === parts[0]) { + devices[i].type = 'virtual'; + } + if ('REMOVABLEMEDIA' === parts[0]) { + devices[i].removable = parts[1] === 'Removable'; + } + if ('PARTITIONTYPE' === parts[0]) { + devices[i].type = 'part'; + } + if ('DEVICE/MEDIANAME' === parts[0]) { + devices[i].model = parts[1]; } - if ('PROTOCOL' === parts[0]) { devices[i].protocol = parts[1]; } - if ('DISKSIZE' === parts[0]) { devices[i].size = parseBytes(parts[1]); } - if ('FILESYSTEMPERSONALITY' === parts[0]) { devices[i].fsType = parts[1]; } - if ('MOUNTPOINT' === parts[0]) { devices[i].mount = parts[1]; } - if ('VOLUMEUUID' === parts[0]) { devices[i].uuid = parts[1]; } - if ('READ-ONLYMEDIA' === parts[0] && parts[1] === 'Yes') { devices[i].physical = 'CD/DVD'; } - if ('SOLIDSTATE' === parts[0] && parts[1] === 'Yes') { devices[i].physical = 'SSD'; } - if ('VIRTUAL' === parts[0]) { devices[i].type = 'virtual'; } - if ('REMOVABLEMEDIA' === parts[0]) { devices[i].removable = (parts[1] === 'Removable'); } - if ('PARTITIONTYPE' === parts[0]) { devices[i].type = 'part'; } - if ('DEVICE/MEDIANAME' === parts[0]) { devices[i].model = parts[1]; } } } } @@ -373,30 +430,32 @@ function parseDevices(lines) { function parseBlk(lines) { let data = []; - lines.filter(line => line !== '').forEach((line) => { - try { - line = decodeURIComponent(line.replace(/\\x/g, '%')); - line = line.replace(/\\/g, '\\\\'); - let disk = JSON.parse(line); - data.push({ - 'name': disk.name, - 'type': disk.type, - 'fsType': disk.fsType, - 'mount': disk.mountpoint, - 'size': parseInt(disk.size), - 'physical': (disk.type === 'disk' ? (disk.rota === '0' ? 'SSD' : 'HDD') : (disk.type === 'rom' ? 'CD/DVD' : '')), - 'uuid': disk.uuid, - 'label': disk.label, - 'model': (disk.model || '').trim(), - 'serial': disk.serial, - 'removable': disk.rm === '1', - 'protocol': disk.tran, - 'group': disk.group || '', - }); - } catch (e) { - util.noop(); - } - }); + lines + .filter((line) => line !== '') + .forEach((line) => { + try { + line = decodeURIComponent(line.replace(/\\x/g, '%')); + line = line.replace(/\\/g, '\\\\'); + const disk = JSON.parse(line); + data.push({ + name: util.sanitizeShellString(disk.name), + type: disk.type, + fsType: disk.fsType, + mount: disk.mountpoint, + size: parseInt(disk.size, 10), + physical: disk.type === 'disk' ? (disk.rota === '0' ? 'SSD' : 'HDD') : disk.type === 'rom' ? 'CD/DVD' : '', + uuid: disk.uuid, + label: disk.label, + model: (disk.model || '').trim(), + serial: disk.serial, + removable: disk.rm === '1', + protocol: disk.tran, + group: disk.group || '' + }); + } catch { + util.noop(); + } + }); data = util.unique(data); data = util.sortByKey(data, ['type', 'name']); return data; @@ -407,7 +466,7 @@ function decodeMdabmData(lines) { const label = util.getValue(lines, 'md_name', '='); // <- get label info const uuid = util.getValue(lines, 'md_uuid', '='); // <- get uuid info const members = []; - lines.forEach(line => { + lines.forEach((line) => { if (line.toLowerCase().startsWith('md_device_dev') && line.toLowerCase().indexOf('/dev/') > 0) { members.push(line.split('/dev/')[1]); } @@ -424,7 +483,7 @@ function raidMatchLinux(data) { // for all block devices of type "raid%" let result = data; try { - data.forEach(element => { + data.forEach((element) => { if (element.type.startsWith('raid')) { const lines = execSync(`mdadm --export --detail /dev/${element.name}`, util.execOptsLinux).toString().split('\n'); const mdData = decodeMdabmData(lines); @@ -432,8 +491,8 @@ function raidMatchLinux(data) { element.label = mdData.label; // <- assign label info element.uuid = mdData.uuid; // <- assign uuid info - if (mdData.members && mdData.members.length && mdData.raid === element.type) { - result = result.map(blockdevice => { + if (mdData.members?.length && mdData.raid === element.type) { + result = result.map((blockdevice) => { if (blockdevice.fsType === 'linux_raid_member' && mdData.members.indexOf(blockdevice.name) >= 0) { blockdevice.group = element.name; } @@ -442,7 +501,7 @@ function raidMatchLinux(data) { } } }); - } catch (e) { + } catch { util.noop(); } return result; @@ -450,7 +509,7 @@ function raidMatchLinux(data) { function getDevicesLinux(data) { const result = []; - data.forEach(element => { + data.forEach((element) => { if (element.type.startsWith('disk')) { result.push(element.name); } @@ -462,9 +521,9 @@ function matchDevicesLinux(data) { let result = data; try { const devices = getDevicesLinux(data); - result = result.map(blockdevice => { + result = result.map((blockdevice) => { if (blockdevice.type.startsWith('part') || blockdevice.type.startsWith('disk')) { - devices.forEach(element => { + devices.forEach((element) => { if (blockdevice.name.startsWith(element)) { blockdevice.device = '/dev/' + element; } @@ -472,7 +531,7 @@ function matchDevicesLinux(data) { } return blockdevice; }); - } catch (e) { + } catch { util.noop(); } return result; @@ -480,13 +539,13 @@ function matchDevicesLinux(data) { function getDevicesMac(data) { const result = []; - data.forEach(element => { + data.forEach((element) => { if (element.type.startsWith('disk')) { result.push({ name: element.name, model: element.model, device: element.name }); } if (element.type.startsWith('virtual')) { let device = ''; - result.forEach(e => { + result.forEach((e) => { if (e.model === element.model) { device = e.device; } @@ -503,9 +562,9 @@ function matchDevicesMac(data) { let result = data; try { const devices = getDevicesMac(data); - result = result.map(blockdevice => { + result = result.map((blockdevice) => { if (blockdevice.type.startsWith('part') || blockdevice.type.startsWith('disk') || blockdevice.type.startsWith('virtual')) { - devices.forEach(element => { + devices.forEach((element) => { if (blockdevice.name.startsWith(element.name)) { blockdevice.device = element.device; } @@ -513,7 +572,7 @@ function matchDevicesMac(data) { } return blockdevice; }); - } catch (e) { + } catch { util.noop(); } return result; @@ -521,13 +580,13 @@ function matchDevicesMac(data) { function getDevicesWin(diskDrives) { const result = []; - diskDrives.forEach(element => { + diskDrives.forEach((element) => { const lines = element.split('\r\n'); const device = util.getValue(lines, 'DeviceID', ':'); let partitions = element.split('@{DeviceID='); if (partitions.length > 1) { partitions = partitions.slice(1); - partitions.forEach(partition => { + partitions.forEach((partition) => { result.push({ name: partition.split(';')[0].toUpperCase(), device }); }); } @@ -537,8 +596,10 @@ function getDevicesWin(diskDrives) { function matchDevicesWin(data, diskDrives) { const devices = getDevicesWin(diskDrives); - data.map(element => { - const filteresDevices = devices.filter((e) => { return e.name === element.name.toUpperCase(); }); + data.map((element) => { + const filteresDevices = devices.filter((e) => { + return e.name === element.name.toUpperCase(); + }); if (filteresDevices.length > 0) { element.device = filteresDevices[0].device; } @@ -548,7 +609,8 @@ function matchDevicesWin(data, diskDrives) { } function blkStdoutToObject(stdout) { - return stdout.toString() + return stdout + .toString() .replace(/NAME=/g, '{"name":') .replace(/FSTYPE=/g, ',"fsType":') .replace(/TYPE=/g, ',"type":') @@ -568,16 +630,15 @@ function blkStdoutToObject(stdout) { } function blockDevices(callback) { - return new Promise((resolve) => { process.nextTick(() => { let data = []; if (_linux) { // see https://wiki.ubuntuusers.de/lsblk/ // exec("lsblk -bo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,TRAN,SERIAL,LABEL,MODEL,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,SCHED,RQ-SIZE,RA,WSAME", function (error, stdout) { - const procLsblk1 = exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,TRAN,SERIAL,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + const procLsblk1 = exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,TRAN,SERIAL,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = blkStdoutToObject(stdout).split('\n'); + const lines = blkStdoutToObject(stdout).split('\n'); data = parseBlk(lines); data = raidMatchLinux(data); data = matchDevicesLinux(data); @@ -586,9 +647,9 @@ function blockDevices(callback) { } resolve(data); } else { - const procLsblk2 = exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + const procLsblk2 = exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = blkStdoutToObject(stdout).split('\n'); + const lines = blkStdoutToObject(stdout).split('\n'); data = parseBlk(lines); data = raidMatchLinux(data); } @@ -597,7 +658,7 @@ function blockDevices(callback) { } resolve(data); }); - procLsblk2.on('error', function () { + procLsblk2.on('error', () => { if (callback) { callback(data); } @@ -605,7 +666,7 @@ function blockDevices(callback) { }); } }); - procLsblk1.on('error', function () { + procLsblk1.on('error', () => { if (callback) { callback(data); } @@ -613,9 +674,9 @@ function blockDevices(callback) { }); } if (_darwin) { - const procDskutil = exec('diskutil info -all', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + const procDskutil = exec('diskutil info -all', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = stdout.toString().split('\n'); + const lines = stdout.toString().split('\n'); // parse lines into temp array of devices data = parseDevices(lines); data = matchDevicesMac(data); @@ -625,7 +686,7 @@ function blockDevices(callback) { } resolve(data); }); - procDskutil.on('error', function () { + procDskutil.on('error', () => { if (callback) { callback(data); } @@ -633,25 +694,29 @@ function blockDevices(callback) { }); } if (_sunos) { - if (callback) { callback(data); } + if (callback) { + callback(data); + } resolve(data); } if (_windows) { - let drivetypes = ['Unknown', 'NoRoot', 'Removable', 'Local', 'Network', 'CD/DVD', 'RAM']; + const drivetypes = ['Unknown', 'NoRoot', 'Removable', 'Local', 'Network', 'CD/DVD', 'RAM']; try { // util.wmic('logicaldisk get Caption,Description,DeviceID,DriveType,FileSystem,FreeSpace,Name,Size,VolumeName,VolumeSerialNumber /value').then((stdout, error) => { // util.powerShell('Get-CimInstance Win32_logicaldisk | select Caption,DriveType,Name,FileSystem,Size,VolumeSerialNumber,VolumeName | fl').then((stdout, error) => { const workload = []; workload.push(util.powerShell('Get-CimInstance -ClassName Win32_LogicalDisk | select Caption,DriveType,Name,FileSystem,Size,VolumeSerialNumber,VolumeName | fl')); - workload.push(util.powerShell('Get-WmiObject -Class Win32_diskdrive | Select-Object -Property PNPDeviceId,DeviceID, Model, Size, @{L=\'Partitions\'; E={$_.GetRelated(\'Win32_DiskPartition\').GetRelated(\'Win32_LogicalDisk\') | Select-Object -Property DeviceID, VolumeName, Size, FreeSpace}} | fl')); - util.promiseAll( - workload - ).then((res) => { - let logicalDisks = res.results[0].toString().split(/\n\s*\n/); - let diskDrives = res.results[1].toString().split(/\n\s*\n/); - logicalDisks.forEach(function (device) { - let lines = device.split('\r\n'); - let drivetype = util.getValue(lines, 'drivetype', ':'); + workload.push( + util.powerShell( + "Get-WmiObject -Class Win32_diskdrive | Select-Object -Property PNPDeviceId,DeviceID, Model, Size, @{L='Partitions'; E={$_.GetRelated('Win32_DiskPartition').GetRelated('Win32_LogicalDisk') | Select-Object -Property DeviceID, VolumeName, Size, FreeSpace}} | fl" + ) + ); + util.promiseAll(workload).then((res) => { + const logicalDisks = res.results[0].toString().split(/\n\s*\n/); + const diskDrives = res.results[1].toString().split(/\n\s*\n/); + logicalDisks.forEach((device) => { + const lines = device.split('\r\n'); + const drivetype = util.getValue(lines, 'drivetype', ':'); if (drivetype) { data.push({ name: util.getValue(lines, 'name', ':'), @@ -660,7 +725,7 @@ function blockDevices(callback) { fsType: util.getValue(lines, 'filesystem', ':').toLowerCase(), mount: util.getValue(lines, 'caption', ':'), size: util.getValue(lines, 'size', ':'), - physical: (drivetype >= 0 && drivetype <= 6) ? drivetypes[drivetype] : drivetypes[0], + physical: drivetype >= 0 && drivetype <= 6 ? drivetypes[drivetype] : drivetypes[0], uuid: util.getValue(lines, 'volumeserialnumber', ':'), label: util.getValue(lines, 'volumename', ':'), model: '', @@ -679,17 +744,20 @@ function blockDevices(callback) { } resolve(data); }); - } catch (e) { - if (callback) { callback(data); } + } catch { + if (callback) { + callback(data); + } resolve(data); } } if (_freebsd || _openbsd || _netbsd) { // will follow - if (callback) { callback(null); } + if (callback) { + callback(null); + } resolve(null); } - }); }); } @@ -700,7 +768,7 @@ exports.blockDevices = blockDevices; // FS - speed function calcFsSpeed(rx, wx) { - let result = { + const result = { rx: 0, wx: 0, tx: 0, @@ -710,7 +778,7 @@ function calcFsSpeed(rx, wx) { ms: 0 }; - if (_fs_speed && _fs_speed.ms) { + if (_fs_speed?.ms) { result.rx = rx; result.wx = wx; result.tx = result.rx + result.wx; @@ -743,7 +811,6 @@ function calcFsSpeed(rx, wx) { } function fsStats(callback) { - return new Promise((resolve) => { process.nextTick(() => { if (_windows || _freebsd || _openbsd || _netbsd || _sunos) { @@ -762,31 +829,33 @@ function fsStats(callback) { let rx = 0; let wx = 0; - if ((_fs_speed && !_fs_speed.ms) || (_fs_speed && _fs_speed.ms && Date.now() - _fs_speed.ms >= 500)) { + if ((_fs_speed && !_fs_speed.ms) || (_fs_speed?.ms && Date.now() - _fs_speed.ms >= 500)) { if (_linux) { // exec("df -k | grep /dev/", function(error, stdout) { - const procLsblk = exec('lsblk -r 2>/dev/null | grep /', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + const procLsblk = exec('lsblk -r 2>/dev/null | grep /', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = stdout.toString().split('\n'); - let fs_filter = []; - lines.forEach(function (line) { + const lines = stdout.toString().split('\n'); + const fs_filter = []; + lines.forEach((line) => { if (line !== '') { line = line.trim().split(' '); - if (fs_filter.indexOf(line[0]) === -1) { fs_filter.push(line[0]); } + if (fs_filter.indexOf(line[0]) === -1) { + fs_filter.push(line[0]); + } } }); - let output = fs_filter.join('|'); - const procCat = exec('cat /proc/diskstats | egrep "' + output + '"', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + const output = fs_filter.join('|'); + const procCat = exec('cat /proc/diskstats | egrep "' + output + '"', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { + const lines = stdout.toString().split('\n'); + lines.forEach((line) => { line = line.trim(); if (line !== '') { line = line.replace(/ +/g, ' ').split(' '); - rx += parseInt(line[5]) * 512; - wx += parseInt(line[9]) * 512; + rx += parseInt(line[5], 10) * 512; + wx += parseInt(line[9], 10) * 512; } }); result = calcFsSpeed(rx, wx); @@ -796,7 +865,7 @@ function fsStats(callback) { } resolve(result); }); - procCat.on('error', function () { + procCat.on('error', () => { if (callback) { callback(result); } @@ -809,35 +878,38 @@ function fsStats(callback) { resolve(result); } }); - procLsblk.on('error', function () { + procLsblk.on('error', () => { if (callback) { callback(result); } resolve(result); }); - } if (_darwin) { - const procIoreg = exec('ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', { maxBuffer: 1024 * 1024 }, function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line !== '') { - line = line.split(','); + const procIoreg = exec( + 'ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', + { maxBuffer: 1024 * 1024 }, + (error, stdout) => { + if (!error) { + const lines = stdout.toString().split('\n'); + lines.forEach((line) => { + line = line.trim(); + if (line !== '') { + line = line.split(','); - rx += parseInt(line[2]); - wx += parseInt(line[9]); - } - }); - result = calcFsSpeed(rx, wx); + rx += parseInt(line[2], 10); + wx += parseInt(line[9], 10); + } + }); + result = calcFsSpeed(rx, wx); + } + if (callback) { + callback(result); + } + resolve(result); } - if (callback) { - callback(result); - } - resolve(result); - }); - procIoreg.on('error', function () { + ); + procIoreg.on('error', () => { if (callback) { callback(result); } @@ -864,7 +936,7 @@ function fsStats(callback) { exports.fsStats = fsStats; function calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime) { - let result = { + const result = { rIO: 0, wIO: 0, tIO: 0, @@ -879,7 +951,7 @@ function calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime) { tWaitPercent: null, ms: 0 }; - if (_disk_io && _disk_io.ms) { + if (_disk_io?.ms) { result.rIO = rIO; result.wIO = wIO; result.tIO = rIO + wIO; @@ -890,9 +962,9 @@ function calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime) { result.rWaitTime = rWaitTime; result.wWaitTime = wWaitTime; result.tWaitTime = tWaitTime; - result.rWaitPercent = (result.rWaitTime - _disk_io.rWaitTime) * 100 / (result.ms); - result.wWaitPercent = (result.wWaitTime - _disk_io.wWaitTime) * 100 / (result.ms); - result.tWaitPercent = (result.tWaitTime - _disk_io.tWaitTime) * 100 / (result.ms); + result.rWaitPercent = ((result.rWaitTime - _disk_io.rWaitTime) * 100) / result.ms; + result.wWaitPercent = ((result.wWaitTime - _disk_io.wWaitTime) * 100) / result.ms; + result.tWaitPercent = ((result.tWaitTime - _disk_io.tWaitTime) * 100) / result.ms; _disk_io.rIO = rIO; _disk_io.wIO = wIO; _disk_io.rIO_sec = result.rIO_sec; @@ -931,7 +1003,6 @@ function calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime) { } function disksIO(callback) { - return new Promise((resolve) => { process.nextTick(() => { if (_windows) { @@ -962,27 +1033,30 @@ function disksIO(callback) { let wWaitTime = 0; let tWaitTime = 0; - if ((_disk_io && !_disk_io.ms) || (_disk_io && _disk_io.ms && Date.now() - _disk_io.ms >= 500)) { + if ((_disk_io && !_disk_io.ms) || (_disk_io?.ms && Date.now() - _disk_io.ms >= 500)) { if (_linux || _freebsd || _openbsd || _netbsd) { // prints Block layer statistics for all mounted volumes // var cmd = "for mount in `lsblk | grep / | sed -r 's/│ └─//' | cut -d ' ' -f 1`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; // var cmd = "for mount in `lsblk | grep / | sed 's/[│└─├]//g' | awk '{$1=$1};1' | cut -d ' ' -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; - let cmd = 'for mount in `lsblk 2>/dev/null | grep " disk " | sed "s/[│└─├]//g" | awk \'{$1=$1};1\' | cut -d " " -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r "s/ +/;/g" | sed -r "s/^;//"; done'; + const cmd = + 'for mount in `lsblk 2>/dev/null | grep " disk " | sed "s/[│└─├]//g" | awk \'{$1=$1};1\' | cut -d " " -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r "s/ +/;/g" | sed -r "s/^;//"; done'; - exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) { + exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { - let lines = stdout.split('\n'); - lines.forEach(function (line) { + const lines = stdout.split('\n'); + lines.forEach((line) => { // ignore empty lines - if (!line) { return; } + if (!line) { + return; + } // sum r/wIO of all disks to compute all disks IO - let stats = line.split(';'); - rIO += parseInt(stats[0]); - wIO += parseInt(stats[4]); - rWaitTime += parseInt(stats[3]); - wWaitTime += parseInt(stats[7]); - tWaitTime += parseInt(stats[10]); + const stats = line.split(';'); + rIO += parseInt(stats[0], 10); + wIO += parseInt(stats[4], 10); + rWaitTime += parseInt(stats[3], 10); + wWaitTime += parseInt(stats[7], 10); + tWaitTime += parseInt(stats[10], 10); }); result = calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime); @@ -999,25 +1073,29 @@ function disksIO(callback) { }); } if (_darwin) { - exec('ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', { maxBuffer: 1024 * 1024 }, function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line !== '') { - line = line.split(','); + exec( + 'ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', + { maxBuffer: 1024 * 1024 }, + (error, stdout) => { + if (!error) { + const lines = stdout.toString().split('\n'); + lines.forEach((line) => { + line = line.trim(); + if (line !== '') { + line = line.split(','); - rIO += parseInt(line[10]); - wIO += parseInt(line[0]); - } - }); - result = calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime); + rIO += parseInt(line[10], 10); + wIO += parseInt(line[0], 10); + } + }); + result = calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime); + } + if (callback) { + callback(result); + } + resolve(result); } - if (callback) { - callback(result); - } - resolve(result); - }); + ); } } else { result.rIO = _disk_io.rIO; @@ -1045,7 +1123,6 @@ function disksIO(callback) { exports.disksIO = disksIO; function diskLayout(callback) { - function getVendorFromModel(model) { const diskManufacturers = [ { pattern: 'WESTERN.*', manufacturer: 'Western Digital' }, @@ -1078,7 +1155,7 @@ function diskLayout(callback) { { pattern: 'ECM.*', manufacturer: 'ECM' }, { pattern: 'INTEL.*', manufacturer: 'INTEL' }, { pattern: 'EVO.*', manufacturer: 'Samsung' }, - { pattern: 'APPLE.*', manufacturer: 'Apple' }, + { pattern: 'APPLE.*', manufacturer: 'Apple' } ]; let result = ''; @@ -1086,7 +1163,9 @@ function diskLayout(callback) { model = model.toUpperCase(); diskManufacturers.forEach((manufacturer) => { const re = RegExp(manufacturer.pattern); - if (re.test(model)) { result = manufacturer.manufacturer; } + if (re.test(model)) { + result = manufacturer.manufacturer; + } }); } return result; @@ -1094,8 +1173,7 @@ function diskLayout(callback) { return new Promise((resolve) => { process.nextTick(() => { - - const commitResult = res => { + const commitResult = (res) => { for (let i = 0; i < res.length; i++) { delete res[i].BSDName; } @@ -1105,13 +1183,13 @@ function diskLayout(callback) { resolve(res); }; - let result = []; + const result = []; let cmd = ''; if (_linux) { let cmdFullSmart = ''; - exec('export LC_ALL=C; lsblk -ablJO 2>/dev/null; unset LC_ALL', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + exec('export LC_ALL=C; lsblk -ablJO 2>/dev/null; unset LC_ALL', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { try { const out = stdout.toString().trim(); @@ -1119,16 +1197,36 @@ function diskLayout(callback) { try { const outJSON = JSON.parse(out); if (outJSON && {}.hasOwnProperty.call(outJSON, 'blockdevices')) { - devices = outJSON.blockdevices.filter(item => { return (item.type === 'disk') && item.size > 0 && (item.model !== null || (item.mountpoint === null && item.label === null && item.fstype === null && item.parttype === null && item.path && item.path.indexOf('/ram') !== 0 && item.path.indexOf('/loop') !== 0 && item['disc-max'] && item['disc-max'] !== 0)); }); + devices = outJSON.blockdevices.filter((item) => { + return ( + item.type === 'disk' && + item.size > 0 && + (item.model !== null || + (item.mountpoint === null && + item.label === null && + item.fstype === null && + item.parttype === null && + item.path && + item.path.indexOf('/ram') !== 0 && + item.path.indexOf('/loop') !== 0 && + item['disc-max'] && + item['disc-max'] !== 0)) + ); + }); } - } catch (e) { + } catch { // fallback to older version of lsblk try { - const out2 = execSync('export LC_ALL=C; lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER,GROUP 2>/dev/null; unset LC_ALL', util.execOptsLinux).toString(); - let lines = blkStdoutToObject(out2).split('\n'); + const out2 = execSync( + 'export LC_ALL=C; lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER,GROUP 2>/dev/null; unset LC_ALL', + util.execOptsLinux + ).toString(); + const lines = blkStdoutToObject(out2).split('\n'); const data = parseBlk(lines); - devices = data.filter(item => { return (item.type === 'disk') && item.size > 0 && ((item.model !== null && item.model !== '') || (item.mount === '' && item.label === '' && item.fsType === '')); }); - } catch (e) { + devices = data.filter((item) => { + return item.type === 'disk' && item.size > 0 && ((item.model !== null && item.model !== '') || (item.mount === '' && item.label === '' && item.fsType === '')); + }); + } catch { util.noop(); } } @@ -1137,8 +1235,10 @@ function diskLayout(callback) { const BSDName = '/dev/' + device.name; const logical = device.name; try { - mediumType = execSync('cat /sys/block/' + logical + '/queue/rotational 2>/dev/null', util.execOptsLinux).toString().split('\n')[0]; - } catch (e) { + mediumType = execSync('cat /sys/block/' + logical + '/queue/rotational 2>/dev/null', util.execOptsLinux) + .toString() + .split('\n')[0]; + } catch { util.noop(); } let interfaceType = device.tran ? device.tran.toUpperCase().trim() : ''; @@ -1148,7 +1248,18 @@ function diskLayout(callback) { } result.push({ device: BSDName, - type: (mediumType === '0' ? 'SSD' : (mediumType === '1' ? 'HD' : (mediumType === '2' ? 'NVMe' : (device.model && device.model.indexOf('SSD') > -1 ? 'SSD' : (device.model && device.model.indexOf('NVM') > -1 ? 'NVMe' : 'HD'))))), + type: + mediumType === '0' + ? 'SSD' + : mediumType === '1' + ? 'HD' + : mediumType === '2' + ? 'NVMe' + : device.model && device.model.indexOf('SSD') > -1 + ? 'SSD' + : device.model && device.model.indexOf('NVM') > -1 + ? 'NVMe' + : 'HD', name: device.model || '', vendor: getVendorFromModel(device.model) || (device.vendor ? device.vendor.trim() : ''), size: device.size || 0, @@ -1169,22 +1280,22 @@ function diskLayout(callback) { cmd += `printf "\n${BSDName}|"; smartctl -H ${BSDName} | grep overall;`; cmdFullSmart += `${cmdFullSmart ? 'printf ",";' : ''}smartctl -a -j ${BSDName};`; }); - } catch (e) { + } catch { util.noop(); } } // check S.M.A.R.T. status if (cmdFullSmart) { - exec(cmdFullSmart, { maxBuffer: 1024 * 1024 }, function (error, stdout) { + exec(cmdFullSmart, { maxBuffer: 1024 * 1024 }, (error, stdout) => { try { const data = JSON.parse(`[${stdout}]`); - data.forEach(disk => { + 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].smartStatus = disk.smart_status.passed ? 'Ok' : disk.smart_status.passed === false ? 'Predicted Failure' : 'unknown'; + if (disk.temperature?.current) { result[i].temperature = disk.temperature.current; } result[i].smartData = disk; @@ -1192,24 +1303,24 @@ function diskLayout(callback) { } }); commitResult(result); - } catch (e) { + } catch { if (cmd) { cmd = cmd + 'printf "\n"'; - exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) { - let lines = stdout.toString().split('\n'); - lines.forEach(line => { + exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => { + const lines = stdout.toString().split('\n'); + lines.forEach((line) => { if (line) { - let parts = line.split('|'); + const parts = line.split('|'); if (parts.length === 2) { - let BSDName = parts[0]; + const BSDName = parts[0]; parts[1] = parts[1].trim(); - let parts2 = parts[1].split(':'); + const parts2 = parts[1].split(':'); if (parts2.length === 2) { parts2[1] = parts2[1].trim(); - let status = parts2[1].toLowerCase(); + 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')); + result[i].smartStatus = status === 'passed' ? 'Ok' : status === 'failed!' ? 'Predicted Failure' : 'unknown'; } } } @@ -1229,47 +1340,65 @@ function diskLayout(callback) { }); } if (_freebsd || _openbsd || _netbsd) { - if (callback) { callback(result); } + if (callback) { + callback(result); + } resolve(result); } if (_sunos) { - if (callback) { callback(result); } + if (callback) { + callback(result); + } resolve(result); } if (_darwin) { - exec('system_profiler SPSerialATADataType SPNVMeDataType SPUSBDataType', { maxBuffer: 1024 * 1024 }, function (error, stdout) { + exec('system_profiler SPSerialATADataType SPNVMeDataType SPUSBDataType', { maxBuffer: 1024 * 1024 }, (error, stdout) => { if (!error) { // split by type: - let lines = stdout.toString().split('\n'); - let linesSATA = []; - let linesNVMe = []; - let linesUSB = []; + const lines = stdout.toString().split('\n'); + const linesSATA = []; + const linesNVMe = []; + const linesUSB = []; let dataType = 'SATA'; - lines.forEach(line => { - if (line === 'NVMExpress:') { dataType = 'NVMe'; } - else if (line === 'USB:') { dataType = 'USB'; } - else if (line === 'SATA/SATA Express:') { dataType = 'SATA'; } - else if (dataType === 'SATA') { linesSATA.push(line); } - else if (dataType === 'NVMe') { linesNVMe.push(line); } - else if (dataType === 'USB') { linesUSB.push(line); } + lines.forEach((line) => { + if (line === 'NVMExpress:') { + dataType = 'NVMe'; + } else if (line === 'USB:') { + dataType = 'USB'; + } else if (line === 'SATA/SATA Express:') { + dataType = 'SATA'; + } else if (dataType === 'SATA') { + linesSATA.push(line); + } else if (dataType === 'NVMe') { + linesNVMe.push(line); + } else if (dataType === 'USB') { + linesUSB.push(line); + } }); try { // Serial ATA Drives - let devices = linesSATA.join('\n').split(' Physical Interconnect: '); + const devices = linesSATA.join('\n').split(' Physical Interconnect: '); devices.shift(); - devices.forEach(function (device) { + devices.forEach((device) => { device = 'InterfaceType: ' + device; - let lines = device.split('\n'); + const lines = device.split('\n'); const mediumType = util.getValue(lines, 'Medium Type', ':', true).trim(); const sizeStr = util.getValue(lines, 'capacity', ':', true).trim(); const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim(); if (sizeStr) { let sizeValue = 0; if (sizeStr.indexOf('(') >= 0) { - sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/\s/g, '')); + sizeValue = parseInt( + sizeStr + .match(/\(([^)]+)\)/)[1] + .replace(/\./g, '') + .replace(/,/g, '') + .replace(/\s/g, ''), + 10 + ); } if (!sizeValue) { - sizeValue = parseInt(sizeStr); + sizeValue = parseInt(sizeStr, 10); } if (sizeValue) { const smartStatusString = util.getValue(lines, 'S.M.A.R.T. status', ':', true).trim().toLowerCase(); @@ -1297,27 +1426,34 @@ function diskLayout(callback) { } } }); - } catch (e) { + } catch { util.noop(); } // NVME Drives try { - let devices = linesNVMe.join('\n').split('\n\n Capacity:'); + const devices = linesNVMe.join('\n').split('\n\n Capacity:'); devices.shift(); - devices.forEach(function (device) { - device = '!Capacity: ' + device; - let lines = device.split('\n'); + devices.forEach((device) => { + device = `!Capacity: ${device}`; + const lines = device.split('\n'); const linkWidth = util.getValue(lines, 'link width', ':', true).trim(); const sizeStr = util.getValue(lines, '!capacity', ':', true).trim(); const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim(); if (sizeStr) { let sizeValue = 0; if (sizeStr.indexOf('(') >= 0) { - sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/\s/g, '')); + sizeValue = parseInt( + sizeStr + .match(/\(([^)]+)\)/)[1] + .replace(/\./g, '') + .replace(/,/g, '') + .replace(/\s/g, ''), + 10 + ); } if (!sizeValue) { - sizeValue = parseInt(sizeStr); + sizeValue = parseInt(sizeStr, 10); } if (sizeValue) { const smartStatusString = util.getValue(lines, 'S.M.A.R.T. status', ':', true).trim().toLowerCase(); @@ -1341,28 +1477,35 @@ function diskLayout(callback) { temperature: null, BSDName: BSDName }); - cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;'; + cmd = `${cmd}printf "\n${BSDName}|"; diskutil info /dev/${BSDName} | grep SMART;`; } } }); - } catch (e) { + } catch { util.noop(); } // USB Drives try { - let devices = linesUSB.join('\n').replaceAll('Media:\n ', 'Model:').split('\n\n Product ID:'); + const devices = linesUSB.join('\n').replaceAll('Media:\n ', 'Model:').split('\n\n Product ID:'); devices.shift(); - devices.forEach(function (device) { - let lines = device.split('\n'); + devices.forEach((device) => { + const lines = device.split('\n'); const sizeStr = util.getValue(lines, 'Capacity', ':', true).trim(); const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim(); if (sizeStr) { let sizeValue = 0; if (sizeStr.indexOf('(') >= 0) { - sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/\s/g, '')); + sizeValue = parseInt( + sizeStr + .match(/\(([^)]+)\)/)[1] + .replace(/\./g, '') + .replace(/,/g, '') + .replace(/\s/g, ''), + 10 + ); } if (!sizeValue) { - sizeValue = parseInt(sizeStr); + sizeValue = parseInt(sizeStr, 10); } if (sizeValue) { const smartStatusString = util.getValue(lines, 'S.M.A.R.T. status', ':', true).trim().toLowerCase(); @@ -1390,26 +1533,26 @@ function diskLayout(callback) { } } }); - } catch (e) { + } catch { util.noop(); } if (cmd) { cmd = cmd + 'printf "\n"'; - exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) { - let lines = stdout.toString().split('\n'); - lines.forEach(line => { + exec(cmd, { maxBuffer: 1024 * 1024 }, (error, stdout) => { + const lines = stdout.toString().split('\n'); + lines.forEach((line) => { if (line) { - let parts = line.split('|'); + const parts = line.split('|'); if (parts.length === 2) { - let BSDName = parts[0]; + const BSDName = parts[0]; parts[1] = parts[1].trim(); - let parts2 = parts[1].split(':'); + const parts2 = parts[1].split(':'); if (parts2.length === 2) { parts2[1] = parts2[1].trim(); - let status = parts2[1].toLowerCase(); + const status = parts2[1].toLowerCase(); for (let i = 0; i < result.length; i++) { if (result[i].BSDName === BSDName) { - result[i].smartStatus = (status === 'not supported' ? 'not supported' : (status === 'verified' ? 'Ok' : (status === 'failing' ? 'Predicted Failure' : 'unknown'))); + result[i].smartStatus = status === 'not supported' ? 'not supported' : status === 'verified' ? 'Ok' : status === 'failing' ? 'Predicted Failure' : 'unknown'; } } } @@ -1429,69 +1572,79 @@ function diskLayout(callback) { if (_windows) { try { const workload = []; - workload.push(util.powerShell('Get-CimInstance Win32_DiskDrive | select Caption,Size,Status,PNPDeviceId,DeviceId,BytesPerSector,TotalCylinders,TotalHeads,TotalSectors,TotalTracks,TracksPerCylinder,SectorsPerTrack,FirmwareRevision,SerialNumber,InterfaceType | fl')); + workload.push( + util.powerShell( + 'Get-CimInstance Win32_DiskDrive | select Caption,Size,Status,PNPDeviceId,DeviceId,BytesPerSector,TotalCylinders,TotalHeads,TotalSectors,TotalTracks,TracksPerCylinder,SectorsPerTrack,FirmwareRevision,SerialNumber,InterfaceType | fl' + ) + ); workload.push(util.powerShell('Get-PhysicalDisk | select BusType,MediaType,FriendlyName,Model,SerialNumber,Size | fl')); if (util.smartMonToolsInstalled()) { try { const smartDev = JSON.parse(execSync('smartctl --scan -j').toString()); - if (smartDev && smartDev.devices && smartDev.devices.length > 0) { + if (smartDev?.devices && smartDev.devices.length > 0) { smartDev.devices.forEach((dev) => { workload.push(execPromiseSave(`smartctl -j -a ${dev.name}`, util.execOptsWin)); }); } - } catch (e) { + } catch { util.noop(); } } - util.promiseAll( - workload - ).then((data) => { + 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'); + devices.forEach((device) => { + const lines = device.split('\r\n'); const size = util.getValue(lines, 'Size', ':').trim(); const status = util.getValue(lines, 'Status', ':').trim().toLowerCase(); if (size) { result.push({ - device: util.getValue(lines, 'DeviceId', ':'), // changed from PNPDeviceId to DeviceID (be be able to match devices) - type: device.indexOf('SSD') > -1 ? 'SSD' : 'HD', // just a starting point ... better: MSFT_PhysicalDisk - Media Type ... see below + device: util.getValue(lines, 'DeviceId', ':'), // changed from PNPDeviceId to DeviceID (be be able to match devices) + type: device.indexOf('SSD') > -1 ? 'SSD' : 'HD', // just a starting point ... better: MSFT_PhysicalDisk - Media Type ... see below name: util.getValue(lines, 'Caption', ':'), vendor: getVendorFromModel(util.getValue(lines, 'Caption', ':', true).trim()), - size: parseInt(size), - bytesPerSector: parseInt(util.getValue(lines, 'BytesPerSector', ':')), - totalCylinders: parseInt(util.getValue(lines, 'TotalCylinders', ':')), - totalHeads: parseInt(util.getValue(lines, 'TotalHeads', ':')), - totalSectors: parseInt(util.getValue(lines, 'TotalSectors', ':')), - totalTracks: parseInt(util.getValue(lines, 'TotalTracks', ':')), - tracksPerCylinder: parseInt(util.getValue(lines, 'TracksPerCylinder', ':')), - sectorsPerTrack: parseInt(util.getValue(lines, 'SectorsPerTrack', ':')), + size: parseInt(size, 10), + bytesPerSector: parseInt(util.getValue(lines, 'BytesPerSector', ':'), 10), + totalCylinders: parseInt(util.getValue(lines, 'TotalCylinders', ':'), 10), + totalHeads: parseInt(util.getValue(lines, 'TotalHeads', ':'), 10), + totalSectors: parseInt(util.getValue(lines, 'TotalSectors', ':'), 10), + totalTracks: parseInt(util.getValue(lines, 'TotalTracks', ':'), 10), + tracksPerCylinder: parseInt(util.getValue(lines, 'TracksPerCylinder', ':'), 10), + sectorsPerTrack: parseInt(util.getValue(lines, 'SectorsPerTrack', ':'), 10), firmwareRevision: util.getValue(lines, 'FirmwareRevision', ':').trim(), serialNum: util.getValue(lines, 'SerialNumber', ':').trim(), interfaceType: util.getValue(lines, 'InterfaceType', ':').trim(), - smartStatus: (status === 'ok' ? 'Ok' : (status === 'degraded' ? 'Degraded' : (status === 'pred fail' ? 'Predicted Failure' : 'Unknown'))), - temperature: null, + smartStatus: status === 'ok' ? 'Ok' : status === 'degraded' ? 'Degraded' : status === 'pred fail' ? 'Predicted Failure' : 'Unknown', + temperature: null }); } }); devices = data.results[1].split(/\n\s*\n/); - devices.forEach(function (device) { - let lines = device.split('\r\n'); + devices.forEach((device) => { + const 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 (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) { + if (i !== -1) { result[i].type = mediaType; result[i].interfaceType = interfaceType; } @@ -1506,16 +1659,16 @@ function diskLayout(callback) { 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 && smartData.smart_status.passed ? 'Ok' : (smartData.smart_status && smartData.smart_status.passed === false ? 'Predicted Failure' : 'unknown')); - if (smartData.temperature && smartData.temperature.current) { + const i = util.findObjectByKey(result, 'serialNum', serialNum); + if (i !== -1) { + result[i].smartStatus = smartData.smart_status?.passed ? 'Ok' : smartData.smart_status && smartData.smart_status.passed === false ? 'Predicted Failure' : 'unknown'; + if (smartData.temperature?.current) { result[i].temperature = smartData.temperature.current; } result[i].smartData = smartData; } } - } catch (e) { + } catch { util.noop(); } }); @@ -1525,8 +1678,10 @@ function diskLayout(callback) { } resolve(result); }); - } catch (e) { - if (callback) { callback(result); } + } catch { + if (callback) { + callback(result); + } resolve(result); } } diff --git a/lib/util.js b/lib/util.js index f3b5dd7..9c4a840 100644 --- a/lib/util.js +++ b/lib/util.js @@ -22,12 +22,12 @@ const execSync = require('child_process').execSync; const util = require('util'); let _platform = process.platform; -const _linux = (_platform === 'linux' || _platform === 'android'); -const _darwin = (_platform === 'darwin'); -const _windows = (_platform === 'win32'); -const _freebsd = (_platform === 'freebsd'); -const _openbsd = (_platform === 'openbsd'); -const _netbsd = (_platform === 'netbsd'); +const _linux = _platform === 'linux' || _platform === 'android'; +const _darwin = _platform === 'darwin'; +const _windows = _platform === 'win32'; +const _freebsd = _platform === 'freebsd'; +const _openbsd = _platform === 'openbsd'; +const _netbsd = _platform === 'netbsd'; let _cores = 0; let wmicPath = ''; @@ -105,7 +105,9 @@ function unique(obj) { let stringify = {}; for (let i = 0; i < obj.length; i++) { let keys = Object.keys(obj[i]); - keys.sort(function (a, b) { return a - b; }); + keys.sort(function (a, b) { + return a - b; + }); let str = ''; for (let j = 0; j < keys.length; j++) { str += JSON.stringify(keys[j]); @@ -124,9 +126,10 @@ function sortByKey(array, keys) { let x = ''; let y = ''; keys.forEach(function (key) { - x = x + a[key]; y = y + b[key]; + x = x + a[key]; + y = y + b[key]; }); - return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + return x < y ? -1 : x > y ? 1 : 0; }); } @@ -148,7 +151,7 @@ function getValue(lines, property, separator, trimmed, lineMatch) { if (trimmed) { lineLower = lineLower.trim(); } - if (lineLower.startsWith(property) && (lineMatch ? (lineLower.match(property + separator)) || (lineLower.match(property + ' ' + separator)) : true)) { + if (lineLower.startsWith(property) && (lineMatch ? lineLower.match(property + separator) || lineLower.match(property + ' ' + separator) : true)) { const parts = trimmed ? line.trim().split(separator) : line.split(separator); if (parts.length >= 2) { parts.shift(); @@ -170,11 +173,15 @@ function decodeEscapeSequence(str, base) { function detectSplit(str) { let seperator = ''; let part = 0; - str.split('').forEach(element => { + str.split('').forEach((element) => { if (element >= '0' && element <= '9') { - if (part === 1) { part++; } + if (part === 1) { + part++; + } } else { - if (part === 0) { part++; } + if (part === 0) { + part++; + } if (part === 1) { seperator += element; } @@ -194,7 +201,14 @@ function parseTime(t, pmDesignator) { if (parts[2]) { parts[1] += parts[2]; } - let isPM = (parts[1] && (parts[1].toLowerCase().indexOf('pm') > -1) || (parts[1].toLowerCase().indexOf('p.m.') > -1) || (parts[1].toLowerCase().indexOf('p. m.') > -1) || (parts[1].toLowerCase().indexOf('n') > -1) || (parts[1].toLowerCase().indexOf('ch') > -1) || (parts[1].toLowerCase().indexOf('ös') > -1) || (pmDesignator && parts[1].toLowerCase().indexOf(pmDesignator) > -1)); + let isPM = + (parts[1] && parts[1].toLowerCase().indexOf('pm') > -1) || + parts[1].toLowerCase().indexOf('p.m.') > -1 || + parts[1].toLowerCase().indexOf('p. m.') > -1 || + parts[1].toLowerCase().indexOf('n') > -1 || + parts[1].toLowerCase().indexOf('ch') > -1 || + parts[1].toLowerCase().indexOf('ös') > -1 || + (pmDesignator && parts[1].toLowerCase().indexOf(pmDesignator) > -1); hour = parseInt(parts[0], 10); min = parseInt(parts[1], 10); hour = isPM && hour < 12 ? hour + 12 : hour; @@ -209,7 +223,7 @@ function parseDateTime(dt, culture) { }; culture = culture || {}; let dateFormat = (culture.dateFormat || '').toLowerCase(); - let pmDesignator = (culture.pmDesignator || ''); + let pmDesignator = culture.pmDesignator || ''; const parts = dt.split(' '); if (parts[0]) { @@ -221,7 +235,7 @@ function parseDateTime(dt, culture) { // Dateformat: yyyy/mm/dd result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2); } else if (dtparts[2].length === 2) { - if ((dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1)) { + if (dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1) { // Dateformat: mm/dd/yy result.date = '20' + dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2); } else { @@ -230,7 +244,13 @@ function parseDateTime(dt, culture) { } } else { // Dateformat: mm/dd/yyyy or dd/mm/yyyy - const isEN = ((dt.toLowerCase().indexOf('pm') > -1) || (dt.toLowerCase().indexOf('p.m.') > -1) || (dt.toLowerCase().indexOf('p. m.') > -1) || (dt.toLowerCase().indexOf('am') > -1) || (dt.toLowerCase().indexOf('a.m.') > -1) || (dt.toLowerCase().indexOf('a. m.') > -1)); + const isEN = + dt.toLowerCase().indexOf('pm') > -1 || + dt.toLowerCase().indexOf('p.m.') > -1 || + dt.toLowerCase().indexOf('p. m.') > -1 || + dt.toLowerCase().indexOf('am') > -1 || + dt.toLowerCase().indexOf('a.m.') > -1 || + dt.toLowerCase().indexOf('a. m.') > -1; if ((isEN || dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1) && dateFormat.indexOf('dd/') !== 0) { // Dateformat: mm/dd/yyyy result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2); @@ -270,7 +290,7 @@ function parseDateTime(dt, culture) { } function parseHead(head, rights) { - let space = (rights > 0); + let space = rights > 0; let count = 1; let from = 0; let to = 0; @@ -366,7 +386,7 @@ function wmic(command) { return new Promise((resolve) => { process.nextTick(() => { try { - powerShell(getWmic() + ' ' + command).then(stdout => { + powerShell(getWmic() + ' ' + command).then((stdout) => { resolve(stdout, ''); }); } catch (e) { @@ -435,7 +455,9 @@ function powerShellStart() { powerShellProceedResults(_psResult + _psError); }); _psChild.on('close', function () { - if (_psChild) { _psChild.kill(); } + if (_psChild) { + _psChild.kill(); + } }); } } @@ -449,13 +471,14 @@ function powerShellRelease() { _psPersistent = false; } } catch (e) { - if (_psChild) { _psChild.kill(); } + if (_psChild) { + _psChild.kill(); + } } _psChild = null; } function powerShell(cmd) { - /// const pattern = [ /// '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', /// '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))' @@ -483,7 +506,6 @@ function powerShell(cmd) { } }); }); - } else { let result = ''; @@ -640,17 +662,7 @@ function smartMonToolsInstalled() { // https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#hardware-revision-codes function isRaspberry(cpuinfo) { - const PI_MODEL_NO = [ - 'BCM2708', - 'BCM2709', - 'BCM2710', - 'BCM2711', - 'BCM2712', - 'BCM2835', - 'BCM2836', - 'BCM2837', - 'BCM2837B0' - ]; + const PI_MODEL_NO = ['BCM2708', 'BCM2709', 'BCM2710', 'BCM2711', 'BCM2712', 'BCM2835', 'BCM2836', 'BCM2837', 'BCM2837B0']; if (_rpi_cpuinfo !== null) { cpuinfo = _rpi_cpuinfo; } else if (cpuinfo === undefined) { @@ -664,7 +676,7 @@ function isRaspberry(cpuinfo) { const hardware = getValue(cpuinfo, 'hardware'); const model = getValue(cpuinfo, 'model'); - return ((hardware && PI_MODEL_NO.indexOf(hardware) > -1) || (model && model.indexOf('Raspberry Pi') > -1)); + return (hardware && PI_MODEL_NO.indexOf(hardware) > -1) || (model && model.indexOf('Raspberry Pi') > -1); } function isRaspbian() { @@ -675,7 +687,7 @@ function isRaspbian() { return false; } const id = getValue(osrelease, 'id', '='); - return (id && id.indexOf('raspbian') > -1); + return id && id.indexOf('raspbian') > -1; } function execWin(cmd, opts, callback) { @@ -693,7 +705,7 @@ function darwinXcodeExists() { const cmdLineToolsExists = fs.existsSync('/Library/Developer/CommandLineTools/usr/bin/'); const xcodeAppExists = fs.existsSync('/Applications/Xcode.app/Contents/Developer/Tools'); const xcodeExists = fs.existsSync('/Library/Developer/Xcode/'); - return (cmdLineToolsExists || xcodeExists || xcodeAppExists); + return cmdLineToolsExists || xcodeExists || xcodeAppExists; } function nanoSeconds() { @@ -707,7 +719,7 @@ function nanoSeconds() { function countUniqueLines(lines, startingWith) { startingWith = startingWith || ''; const uniqueLines = []; - lines.forEach(line => { + lines.forEach((line) => { if (line.startsWith(startingWith)) { if (uniqueLines.indexOf(line) === -1) { uniqueLines.push(line); @@ -720,7 +732,7 @@ function countUniqueLines(lines, startingWith) { function countLines(lines, startingWith) { startingWith = startingWith || ''; const uniqueLines = []; - lines.forEach(line => { + lines.forEach((line) => { if (line.startsWith(startingWith)) { uniqueLines.push(line); } @@ -729,40 +741,46 @@ function countLines(lines, startingWith) { } function sanitizeShellString(str, strict) { - if (typeof strict === 'undefined') { strict = false; } + if (typeof strict === 'undefined') { + strict = false; + } const s = str || ''; let result = ''; const l = mathMin(s.length, 2000); for (let i = 0; i <= l; i++) { - if (!(s[i] === undefined || - s[i] === '>' || - s[i] === '<' || - s[i] === '*' || - s[i] === '?' || - s[i] === '[' || - s[i] === ']' || - s[i] === '|' || - s[i] === '˚' || - s[i] === '$' || - s[i] === ';' || - s[i] === '&' || - s[i] === ']' || - s[i] === '#' || - s[i] === '\\' || - s[i] === '\t' || - s[i] === '\n' || - s[i] === '\r' || - s[i] === '\'' || - s[i] === '`' || - s[i] === '"' || - s[i].length > 1 || - (strict && s[i] === '(') || - (strict && s[i] === ')') || - (strict && s[i] === '@') || - (strict && s[i] === ' ') || - (strict && s[i] == '{') || - (strict && s[i] == ';') || - (strict && s[i] == '}'))) { + if ( + !( + s[i] === undefined || + s[i] === '>' || + s[i] === '<' || + s[i] === '*' || + s[i] === '?' || + s[i] === '[' || + s[i] === ']' || + s[i] === '|' || + s[i] === '˚' || + s[i] === '$' || + s[i] === ';' || + s[i] === '&' || + s[i] === ']' || + s[i] === '#' || + s[i] === '\\' || + s[i] === '\t' || + s[i] === '\n' || + s[i] === '\r' || + s[i] === "'" || + s[i] === '`' || + s[i] === '"' || + s[i].length > 1 || + (strict && s[i] === '(') || + (strict && s[i] === ')') || + (strict && s[i] === '@') || + (strict && s[i] === ' ') || + (strict && s[i] === '{') || + (strict && s[i] === ';') || + (strict && s[i] === '}') + ) + ) { result = result + s[i]; } } @@ -785,10 +803,10 @@ function isPrototypePolluted() { } catch (e) { Object.setPrototypeOf(st, stringObj); } - notPolluted = notPolluted || (s.length !== 62); + notPolluted = notPolluted || s.length !== 62; const ms = Date.now(); if (typeof ms === 'number' && ms > 1600000000000) { - const l = ms % 100 + 15; + const l = (ms % 100) + 15; for (let i = 0; i < l; i++) { const r = Math.random() * 61.99999999 + 1; const rs = parseInt(Math.floor(r).toString(), 10); @@ -796,7 +814,7 @@ function isPrototypePolluted() { const q = Math.random() * 61.99999999 + 1; const qs = parseInt(Math.floor(q).toString(), 10); const qs2 = parseInt(q.toString().split('.')[0], 10); - notPolluted = notPolluted && (r !== q); + notPolluted = notPolluted && r !== q; notPolluted = notPolluted && rs === rs2 && qs === qs2; st += s[rs - 1]; } @@ -826,7 +844,7 @@ function isPrototypePolluted() { // lower const stl = st.toLowerCase(); - notPolluted = notPolluted && (stl.length === l) && stl[l - 1] && !(stl[l]); + notPolluted = notPolluted && stl.length === l && stl[l - 1] && !stl[l]; for (let i = 0; i < l; i++) { const s1 = st[i]; try { @@ -836,14 +854,14 @@ function isPrototypePolluted() { } const s2 = stl ? stl[i] : ''; const s1l = s1.toLowerCase(); - notPolluted = notPolluted && s1l[0] === s2 && s1l[0] && !(s1l[1]); + notPolluted = notPolluted && s1l[0] === s2 && s1l[0] && !s1l[1]; } } return !notPolluted; } function hex2bin(hex) { - return ('00000000' + (parseInt(hex, 16)).toString(2)).substr(-8); + return ('00000000' + parseInt(hex, 16).toString(2)).substr(-8); } function getFilesInPath(source) { @@ -854,21 +872,35 @@ function getFilesInPath(source) { function isDirectory(source) { return lstatSync(source).isDirectory(); } - function isFile(source) { return lstatSync(source).isFile(); } + function isFile(source) { + return lstatSync(source).isFile(); + } function getDirectories(source) { - return readdirSync(source).map(function (name) { return join(source, name); }).filter(isDirectory); + return readdirSync(source) + .map(function (name) { + return join(source, name); + }) + .filter(isDirectory); } function getFiles(source) { - return readdirSync(source).map(function (name) { return join(source, name); }).filter(isFile); + return readdirSync(source) + .map(function (name) { + return join(source, name); + }) + .filter(isFile); } function getFilesRecursively(source) { try { let dirs = getDirectories(source); let files = dirs - .map(function (dir) { return getFilesRecursively(dir); }) - .reduce(function (a, b) { return a.concat(b); }, []); + .map(function (dir) { + return getFilesRecursively(dir); + }) + .reduce(function (a, b) { + return a.concat(b); + }, []); return files.concat(getFiles(source)); } catch (e) { return []; @@ -883,7 +915,6 @@ function getFilesInPath(source) { } function decodePiCpuinfo(lines) { - if (_rpi_cpuinfo === null) { _rpi_cpuinfo = lines; } else if (lines === undefined) { @@ -1014,21 +1045,8 @@ function decodePiCpuinfo(lines) { } }; - const processorList = [ - 'BCM2835', - 'BCM2836', - 'BCM2837', - 'BCM2711', - 'BCM2712', - ]; - const manufacturerList = [ - 'Sony UK', - 'Egoman', - 'Embest', - 'Sony Japan', - 'Embest', - 'Stadium' - ]; + const processorList = ['BCM2835', 'BCM2836', 'BCM2837', 'BCM2711', 'BCM2712']; + const manufacturerList = ['Sony UK', 'Egoman', 'Embest', 'Sony Japan', 'Embest', 'Stadium']; const typeList = { '00': 'A', '01': 'B', @@ -1044,17 +1062,17 @@ function decodePiCpuinfo(lines) { '0d': '3B+', '0e': '3A+', '0f': 'Internal use only', - '10': 'CM3+', - '11': '4B', - '12': 'Zero 2 W', - '13': '400', - '14': 'CM4', - '15': 'CM4S', - '16': 'Internal use only', - '17': '5', - '18': 'CM5', - '19': '500/500+', - '1a': 'CM5 Lite', + 10: 'CM3+', + 11: '4B', + 12: 'Zero 2 W', + 13: '400', + 14: 'CM4', + 15: 'CM4S', + 16: 'Internal use only', + 17: '5', + 18: 'CM5', + 19: '500/500+', + '1a': 'CM5 Lite' }; const revisionCode = getValue(lines, 'revision', ':', true); @@ -1072,9 +1090,8 @@ function decodePiCpuinfo(lines) { manufacturer: oldRevisionCodes[revisionCode].manufacturer, processor: oldRevisionCodes[revisionCode].processor, type: oldRevisionCodes[revisionCode].type, - revision: oldRevisionCodes[revisionCode].revision, + revision: oldRevisionCodes[revisionCode].revision }; - } else { // new revision code const revision = ('00000000' + getValue(lines, 'revision', ':', true).toLowerCase()).substr(-8); @@ -1083,7 +1100,6 @@ function decodePiCpuinfo(lines) { const processor = processorList[parseInt(revision.substr(4, 1), 10)]; const typeCode = revision.substr(5, 2); - result = { model, serial, @@ -1092,14 +1108,13 @@ function decodePiCpuinfo(lines) { manufacturer, processor, type: {}.hasOwnProperty.call(typeList, typeCode) ? typeList[typeCode] : '', - revision: '1.' + revision.substr(7, 1), + revision: '1.' + revision.substr(7, 1) }; } return result; } function getRpiGpu(cpuinfo) { - if (_rpi_cpuinfo === null && cpuinfo !== undefined) { _rpi_cpuinfo = cpuinfo; } else if (cpuinfo === undefined && _rpi_cpuinfo !== null) { @@ -1114,8 +1129,12 @@ function getRpiGpu(cpuinfo) { } const rpi = decodePiCpuinfo(cpuinfo); - if (rpi.type === '4B' || rpi.type === 'CM4' || rpi.type === 'CM4S' || rpi.type === '400') { return 'VideoCore VI'; } - if (rpi.type === '5' || rpi.type === '500') { return 'VideoCore VII'; } + if (rpi.type === '4B' || rpi.type === 'CM4' || rpi.type === 'CM4S' || rpi.type === '400') { + return 'VideoCore VI'; + } + if (rpi.type === '5' || rpi.type === '500') { + return 'VideoCore VII'; + } return 'VideoCore IV'; } @@ -1123,9 +1142,10 @@ function promiseAll(promises) { const resolvingPromises = promises.map(function (promise) { return new Promise(function (resolve) { let payload = new Array(2); - promise.then(function (result) { - payload[0] = result; - }) + promise + .then(function (result) { + payload[0] = result; + }) .catch(function (error) { payload[1] = error; }) @@ -1139,23 +1159,22 @@ function promiseAll(promises) { const results = []; // Execute all wrapped Promises - return Promise.all(resolvingPromises) - .then(function (items) { - items.forEach(function (payload) { - if (payload[1]) { - errors.push(payload[1]); - results.push(null); - } else { - errors.push(null); - results.push(payload[0]); - } - }); - - return { - errors: errors, - results: results - }; + return Promise.all(resolvingPromises).then(function (items) { + items.forEach(function (payload) { + if (payload[1]) { + errors.push(payload[1]); + results.push(null); + } else { + errors.push(null); + results.push(payload[0]); + } }); + + return { + errors: errors, + results: results + }; + }); } function promisify(nodeStyleFunction) { @@ -1218,24 +1237,50 @@ function plistParser(xmlStr) { while (pos < len) { c = cn; - if (pos + 1 < len) { cn = xmlStr[pos + 1]; } + if (pos + 1 < len) { + cn = xmlStr[pos + 1]; + } if (c === '<') { inTagContent = false; - if (cn === '/') { inTagEnd = true; } - else if (metaData[depth].tagStart) { + if (cn === '/') { + inTagEnd = true; + } else if (metaData[depth].tagStart) { metaData[depth].tagContent = ''; - if (!metaData[depth].data) { metaData[depth].data = metaData[depth].tagStart === 'array' ? [] : {}; } + if (!metaData[depth].data) { + metaData[depth].data = metaData[depth].tagStart === 'array' ? [] : {}; + } depth++; metaData.push({ tagStart: '', tagEnd: '', tagContent: '', key: null, data: null }); inTagStart = true; inTagContent = false; + } else if (!inTagStart) { + inTagStart = true; } - else if (!inTagStart) { inTagStart = true; } } else if (c === '>') { - if (metaData[depth].tagStart === 'true/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/boolean'; metaData[depth].data = true; } - if (metaData[depth].tagStart === 'false/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/boolean'; metaData[depth].data = false; } - if (metaData[depth].tagStart === 'array/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/arrayEmpty'; metaData[depth].data = []; } - if (inTagContent) { inTagContent = false; } + if (metaData[depth].tagStart === 'true/') { + inTagStart = false; + inTagEnd = true; + metaData[depth].tagStart = ''; + metaData[depth].tagEnd = '/boolean'; + metaData[depth].data = true; + } + if (metaData[depth].tagStart === 'false/') { + inTagStart = false; + inTagEnd = true; + metaData[depth].tagStart = ''; + metaData[depth].tagEnd = '/boolean'; + metaData[depth].data = false; + } + if (metaData[depth].tagStart === 'array/') { + inTagStart = false; + inTagEnd = true; + metaData[depth].tagStart = ''; + metaData[depth].tagEnd = '/arrayEmpty'; + metaData[depth].data = []; + } + if (inTagContent) { + inTagContent = false; + } if (inTagStart) { inTagStart = false; inTagContent = true; @@ -1261,18 +1306,31 @@ function plistParser(xmlStr) { metaData[depth].tagContent = ''; metaData[depth].tagStart = ''; metaData[depth].tagEnd = ''; - } - else { + } else { if (metaData[depth].tagEnd === '/key' && metaData[depth].tagContent) { metaData[depth].key = metaData[depth].tagContent; } else { - if (metaData[depth].tagEnd === '/real' && metaData[depth].tagContent) { metaData[depth].data = parseFloat(metaData[depth].tagContent) || 0; } - if (metaData[depth].tagEnd === '/integer' && metaData[depth].tagContent) { metaData[depth].data = parseInt(metaData[depth].tagContent) || 0; } - if (metaData[depth].tagEnd === '/string' && metaData[depth].tagContent) { metaData[depth].data = metaData[depth].tagContent || ''; } - if (metaData[depth].tagEnd === '/boolean') { metaData[depth].data = metaData[depth].tagContent || false; } - if (metaData[depth].tagEnd === '/arrayEmpty') { metaData[depth].data = metaData[depth].tagContent || []; } - if (depth > 0 && metaData[depth - 1].tagStart === 'array') { metaData[depth - 1].data.push(metaData[depth].data); } - if (depth > 0 && metaData[depth - 1].tagStart === 'dict') { metaData[depth - 1].data[metaData[depth].key] = metaData[depth].data; } + if (metaData[depth].tagEnd === '/real' && metaData[depth].tagContent) { + metaData[depth].data = parseFloat(metaData[depth].tagContent) || 0; + } + if (metaData[depth].tagEnd === '/integer' && metaData[depth].tagContent) { + metaData[depth].data = parseInt(metaData[depth].tagContent) || 0; + } + if (metaData[depth].tagEnd === '/string' && metaData[depth].tagContent) { + metaData[depth].data = metaData[depth].tagContent || ''; + } + if (metaData[depth].tagEnd === '/boolean') { + metaData[depth].data = metaData[depth].tagContent || false; + } + if (metaData[depth].tagEnd === '/arrayEmpty') { + metaData[depth].data = metaData[depth].tagContent || []; + } + if (depth > 0 && metaData[depth - 1].tagStart === 'array') { + metaData[depth - 1].data.push(metaData[depth].data); + } + if (depth > 0 && metaData[depth - 1].tagStart === 'dict') { + metaData[depth - 1].data[metaData[depth].key] = metaData[depth].data; + } } metaData[depth].tagContent = ''; metaData[depth].tagStart = ''; @@ -1284,9 +1342,15 @@ function plistParser(xmlStr) { inTagContent = false; } } else { - if (inTagStart) { metaData[depth].tagStart += c; } - if (inTagEnd) { metaData[depth].tagEnd += c; } - if (inTagContent) { metaData[depth].tagContent += c; } + if (inTagStart) { + metaData[depth].tagStart += c; + } + if (inTagEnd) { + metaData[depth].tagEnd += c; + } + if (inTagContent) { + metaData[depth].tagContent += c; + } } pos++; } @@ -1340,15 +1404,22 @@ function semverCompare(v1, v2) { let res = 0; const parts1 = v1.split('.'); const parts2 = v2.split('.'); - if (parts1[0] < parts2[0]) { res = 1; } - else if (parts1[0] > parts2[0]) { res = -1; } - else if (parts1[0] === parts2[0] && parts1.length >= 2 && parts2.length >= 2) { - if (parts1[1] < parts2[1]) { res = 1; } - else if (parts1[1] > parts2[1]) { res = -1; } - else if (parts1[1] === parts2[1]) { + if (parts1[0] < parts2[0]) { + res = 1; + } else if (parts1[0] > parts2[0]) { + res = -1; + } else if (parts1[0] === parts2[0] && parts1.length >= 2 && parts2.length >= 2) { + if (parts1[1] < parts2[1]) { + res = 1; + } else if (parts1[1] > parts2[1]) { + res = -1; + } else if (parts1[1] === parts2[1]) { if (parts1.length >= 3 && parts2.length >= 3) { - if (parts1[2] < parts2[2]) { res = 1; } - else if (parts1[2] > parts2[2]) { res = -1; } + if (parts1[2] < parts2[2]) { + res = 1; + } else if (parts1[2] > parts2[2]) { + res = -1; + } } else if (parts2.length >= 3) { res = 1; } @@ -2522,10 +2593,18 @@ function getAppleModel(key) { }; } const features = []; - if (list[0].size) { features.push(list[0].size); } - if (list[0].processor) { features.push(list[0].processor); } - if (list[0].year) { features.push(list[0].year); } - if (list[0].additional) { features.push(list[0].additional); } + if (list[0].size) { + features.push(list[0].size); + } + if (list[0].processor) { + features.push(list[0].processor); + } + if (list[0].year) { + features.push(list[0].year); + } + if (list[0].additional) { + features.push(list[0].additional); + } return { key: key, model: list[0].name, @@ -2534,12 +2613,12 @@ function getAppleModel(key) { } function checkWebsite(url, timeout = 5000) { - const http = ((url.startsWith('https:') || url.indexOf(':443/') > 0 || url.indexOf(':8443/') > 0) ? require('https') : require('http')); + const http = url.startsWith('https:') || url.indexOf(':443/') > 0 || url.indexOf(':8443/') > 0 ? require('https') : require('http'); const t = Date.now(); return new Promise((resolve) => { const request = http .get(url, function (res) { - res.on('data', () => { }); + res.on('data', () => {}); res.on('end', () => { resolve({ url, @@ -2549,7 +2628,7 @@ function checkWebsite(url, timeout = 5000) { }); }); }) - .on("error", function (e) { + .on('error', function (e) { resolve({ url, statusCode: 404, @@ -2567,12 +2646,12 @@ function checkWebsite(url, timeout = 5000) { }); }); }); -}; +} function cleanString(str) { return str.replace(/To Be Filled By O.E.M./g, ''); } -function noop() { } +function noop() {} exports.toInt = toInt; exports.splitByNumber = splitByNumber;