/* Copyright 2019-2021 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ function trimIdentifiers(val) { for(var v in val) { if (!val[v] || val[v] == 'None' || val[v] == '') { delete val[v]; } } } function trimResults(val) { var i, x; for (i = 0; i < val.length; ++i) { for (x in val[i]) { if (x.startsWith('_')) { delete val[i][x]; } else { if (val[i][x] == null || val[i][x] == 0) { delete val[i][x]; } } } } } function brief(headers, obj) { var i, x; for (x = 0; x < obj.length; ++x) { for (i in obj[x]) { if (!headers.includes(i)) { delete obj[x][i]; } } } return (obj); } function dataHandler(c) { this.str += c.toString(); } function linux_identifiers() { var identifiers = {}; var ret = {}; var values = {}; if (!require('fs').existsSync('/sys/class/dmi/id')) { if(require('fs').existsSync('/sys/firmware/devicetree/base/model')){ if(require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim().startsWith('Raspberry')){ identifiers['board_vendor'] = 'Raspberry Pi'; identifiers['board_name'] = require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim(); identifiers['board_serial'] = require('fs').readFileSync('/sys/firmware/devicetree/base/serial-number').toString().trim(); }else{ throw('Unknown board'); } }else { throw ('this platform does not have DMI statistics'); } } else { var entries = require('fs').readdirSync('/sys/class/dmi/id'); for(var i in entries) { if (require('fs').statSync('/sys/class/dmi/id/' + entries[i]).isFile()) { try { ret[entries[i]] = require('fs').readFileSync('/sys/class/dmi/id/' + entries[i]).toString().trim(); } catch(z) { } if (ret[entries[i]] == 'None') { delete ret[entries[i]];} } } entries = null; identifiers['bios_date'] = ret['bios_date']; identifiers['bios_vendor'] = ret['bios_vendor']; identifiers['bios_version'] = ret['bios_version']; identifiers['bios_serial'] = ret['product_serial']; identifiers['board_name'] = ret['board_name']; identifiers['board_serial'] = ret['board_serial']; identifiers['board_vendor'] = ret['board_vendor']; identifiers['board_version'] = ret['board_version']; identifiers['product_uuid'] = ret['product_uuid']; identifiers['product_name'] = ret['product_name']; } try { identifiers['bios_mode'] = (require('fs').statSync('/sys/firmware/efi').isDirectory() ? 'UEFI': 'Legacy'); } catch (ex) { identifiers['bios_mode'] = 'Legacy'; } var child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', dataHandler); child.stdin.write('cat /proc/cpuinfo | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n"); child.waitExit(); identifiers['cpu_name'] = child.stdout.str.trim(); if (identifiers['cpu_name'] == "") { // CPU BLANK, check lscpu instead child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', dataHandler); child.stdin.write('lscpu | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n"); child.waitExit(); identifiers['cpu_name'] = child.stdout.str.trim(); } child = null; // Fetch GPU info child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', dataHandler); child.stdin.write("lspci | grep ' VGA ' | tr '\\n' '`' | awk '{ a=split($0,lines" + ',"`"); printf "["; for(i=1;i1)'); child.stdin.write(' {'); child.stdin.write(' sub(/^[ \\t]*/,"",tmp[2]);'); child.stdin.write(' gsub(/ /,"",tmp[1]);'); child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", ccx, tmp[1], tmp[2]);'); child.stdin.write(' ccx=",";'); child.stdin.write(' }'); child.stdin.write(' }'); child.stdin.write(' printf("}}");'); child.stdin.write(' comma=",";'); child.stdin.write(' }'); child.stdin.write(' }'); child.stdin.write(' printf("]");'); child.stdin.write("}'\nexit\n"); child.waitExit(); try { var j = JSON.parse(child.stdout.str); var i, key, key2; for (i = 0; i < j.length; ++i) { for (key in j[i]) { delete j[i][key]['ArrayHandle']; delete j[i][key]['ErrorInformationHandle']; for (key2 in j[i][key]) { if (j[i][key][key2] == 'Unknown' || j[i][key][key2] == 'Not Specified' || j[i][key][key2] == '') { delete j[i][key][key2]; } } } } if(j.length > 0){ var mem = {}; for (i = 0; i < j.length; ++i) { for (key in j[i]) { if (mem[key] == null) { mem[key] = []; } mem[key].push(j[i][key]); } } values.linux.memory = mem; } } catch (e) { } child = null; } var usbdevices = require('lib-finder').findBinary('usb-devices'); if (usbdevices != null) { var child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', dataHandler); child.stderr.str = ''; child.stderr.on('data', dataHandler); child.stdin.write(usbdevices + " | tr '\\n' '`' | "); child.stdin.write(" awk '"); child.stdin.write('{'); child.stdin.write(' comma="";'); child.stdin.write(' printf("[");'); child.stdin.write(' len=split($0, group, "``");'); child.stdin.write(' for(i=1;i<=len;++i)'); child.stdin.write(' {'); child.stdin.write(' comma2="";'); child.stdin.write(' xlen=split(group[i], line, "`");'); child.stdin.write(' scount=0;'); child.stdin.write(' for(x=1;x0)'); child.stdin.write(' {'); child.stdin.write(' printf("%s{", comma); comma=",";'); child.stdin.write(' for(x=1;x 0) { const memorySlots = []; if(lines[2].trim().includes('Memory Slots:')) { // OLD MACS WITH SLOTS const Memory = []; const bankMatches = child.stdout.str.trim().match(/BANK \d+\/DIMM\d+:[\s\S]*?(?=(BANK|$))/g); bankMatches.forEach(function(match, index) { const bankInfo = match.match(/BANK (\d+)\/DIMM(\d+):[\s\S]*?Size: (\d+ \w+)[\s\S]*?Type: (\w+)[\s\S]*?Speed: (\d+ \w+)[\s\S]*?Status: (\w+)[\s\S]*?Manufacturer: (0x[0-9A-Fa-f]+)[\s\S]*?Part Number: (0x[0-9A-Fa-f]+)[\s\S]*?Serial Number: (.+)/); if (bankInfo) { const bankIndex = bankInfo[1].trim(); const dimmIndex = bankInfo[2].trim(); const size = bankInfo[3].trim(); const type = bankInfo[4].trim(); const speed = bankInfo[5].trim(); const status = bankInfo[6].trim(); const manufacturer = bankInfo[7].trim(); const partNumber = bankInfo[8].trim(); const serialNumber = bankInfo[9].trim(); Memory.push({ DeviceLocator: "BANK " + bankIndex + "/DIMM" + dimmIndex, Size: size, Type: type, Speed: speed, Status: status, Manufacturer: hexToAscii(manufacturer), PartNumber: hexToAscii(partNumber), SerialNumber: serialNumber, }); } }); memorySlots = Memory; } else { // NEW MACS WITHOUT SLOTS memorySlots.push({ DeviceLocator: "Onboard Memory", Size: lines[2].split(":")[1].trim(), PartNumber: lines[3].split(":")[1].trim(), Manufacturer: lines[4].split(":")[1].trim() }) } ret.darwin.memory = memorySlots; } child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stdin.write('diskutil info -all\nexit\n'); child.waitExit(); var sections = child.stdout.str.split('**********\n'); if(sections.length > 0){ var devices = []; for (var i = 0; i < sections.length; i++) { var lines = sections[i].split('\n'); var deviceInfo = {}; var wholeYes = false; var physicalYes = false; var oldmac = false; for (var j = 0; j < lines.length; j++) { var keyValue = lines[j].split(':'); var key = keyValue[0].trim(); var value = keyValue[1] ? keyValue[1].trim() : ''; if (key === 'Virtual') oldmac = true; if (key === 'Whole' && value === 'Yes') wholeYes = true; if (key === 'Virtual' && value === 'No') physicalYes = true; if(value && key === 'Device / Media Name'){ deviceInfo['Caption'] = value; } if(value && key === 'Disk Size'){ deviceInfo['Size'] = value.split(' ')[0] + ' ' + value.split(' ')[1]; } } if (wholeYes) { if (oldmac) { if (physicalYes) devices.push(deviceInfo); } else { devices.push(deviceInfo); } } } ret.identifiers.storage_devices = devices; } trimIdentifiers(ret.identifiers); child = null; return (ret); } function hexToAscii(hexString) { hexString = hexString.startsWith('0x') ? hexString.slice(2) : hexString; var str = ''; for (var i = 0; i < hexString.length; i += 2) { var hexPair = hexString.substr(i, 2); str += String.fromCharCode(parseInt(hexPair, 16)); } str = str.replace(/[\u007F-\uFFFF]/g, ''); // Remove characters from 0x0080 to 0xFFFF return str.trim(); } function win_chassisType() { var child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', 'SystemEnclosure', 'get', 'ChassisTypes']); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); child.waitExit(); try { var tok = child.stdout.str.split('{')[1].split('}')[0]; var val = tok.split(',')[0]; return (parseInt(val)); } catch (e) { return (2); // unknown } } function win_systemType() { var CSV = '/FORMAT:"' + require('util-language').wmicXslPath + 'csv"'; var child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', 'ComputerSystem', 'get', 'PCSystemType', CSV]); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); child.waitExit(); return (parseInt(child.stdout.str.trim().split(',').pop())); } function win_formFactor(chassistype) { var ret = 'DESKTOP'; switch (chassistype) { case 11: // Handheld case 30: // Tablet case 31: // Convertible case 32: // Detachable ret = 'TABLET'; break; case 9: // Laptop case 10: // Notebook case 14: // Sub Notebook ret = 'LAPTOP'; break; default: ret = win_systemType() == 2 ? 'MOBILE' : 'DESKTOP'; break; } return (ret); } switch(process.platform) { case 'linux': module.exports = { _ObjectID: 'identifiers', get: linux_identifiers }; break; case 'win32': module.exports = { _ObjectID: 'identifiers', get: windows_identifiers, chassisType: win_chassisType, formFactor: win_formFactor, systemType: win_systemType }; break; case 'darwin': module.exports = { _ObjectID: 'identifiers', get: macos_identifiers }; break; default: module.exports = { get: function () { throw ('Unsupported Platform'); } }; break; } module.exports.isDocker = function isDocker() { if (process.platform != 'linux') { return (false); } var child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stdin.write("cat /proc/self/cgroup | tr '\n' '`' | awk -F'`' '{ split($1, res, " + '"/"); if(res[2]=="docker"){print "1";} }\'\nexit\n'); child.waitExit(); return (child.stdout.str != ''); }; module.exports.isBatteryPowered = function isBatteryOperated() { var ret = false; switch(process.platform) { default: break; case 'linux': var devices = require('fs').readdirSync('/sys/class/power_supply'); for (var i in devices) { if (require('fs').readFileSync('/sys/class/power_supply/' + devices[i] + '/type').toString().trim() == 'Battery') { ret = true; break; } } break; case 'win32': var GM = require('_GenericMarshal'); var stats = GM.CreateVariable(12); var kernel32 = GM.CreateNativeProxy('Kernel32.dll'); kernel32.CreateMethod('GetSystemPowerStatus'); if (kernel32.GetSystemPowerStatus(stats).Val != 0) { if(stats.toBuffer()[1] != 128 && stats.toBuffer()[1] != 255) { ret = true; } else { // No Battery detected, so lets check if there is supposed to be one var formFactor = win_formFactor(win_chassisType()); return (formFactor == 'LAPTOP' || formFactor == 'TABLET' || formFactor == 'MOBILE'); } } break; case 'darwin': var child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', function(c){ this.str += c.toString(); }); child.stderr.str = ''; child.stderr.on('data', function(c){ this.str += c.toString(); }); child.stdin.write("pmset -g batt | tr '\\n' '`' | awk -F'`' '{ if(NF>2) { print \"true\"; }}'\nexit\n"); child.waitExit(); if(child.stdout.str.trim() != '') { ret = true; } break; } return (ret); }; module.exports.isVM = function isVM() { var ret = false; var id = this.get(); if (id.linux && id.linux.sys_vendor) { switch (id.linux.sys_vendor) { case 'VMware, Inc.': case 'QEMU': case 'Xen': ret = true; break; default: break; } } if (id.identifiers.bios_vendor) { switch(id.identifiers.bios_vendor) { case 'VMware, Inc.': case 'Xen': case 'SeaBIOS': ret = true; break; default: break; } } if (id.identifiers.board_vendor && id.identifiers.board_vendor == 'VMware, Inc.') { ret = true; } if (id.identifiers.board_name) { switch (id.identifiers.board_name) { case 'VirtualBox': case 'Virtual Machine': ret = true; break; default: break; } } if (process.platform == 'win32' && !ret) { for(var i in id.identifiers.gpu_name) { if(id.identifiers.gpu_name[i].startsWith('VMware ')) { ret = true; break; } } } if (!ret) { ret = this.isDocker(); } return (ret); }; if (process.platform == 'win32') { module.exports.volumes_promise = windows_volumes; } // bios_date = BIOS->ReleaseDate // bios_vendor = BIOS->Manufacturer // bios_version = BIOS->SMBIOSBIOSVersion // board_name = BASEBOARD->Product = ioreg/board-id // board_serial = BASEBOARD->SerialNumber = ioreg/serial-number | ioreg/IOPlatformSerialNumber // board_vendor = BASEBOARD->Manufacturer = ioreg/manufacturer // board_version = BASEBOARD->Version