| 1 | /* |
| 2 | Copyright 2019-2021 Intel Corporation |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | function trimIdentifiers(val) |
| 18 | { |
| 19 | for(var v in val) |
| 20 | { |
| 21 | if(typeof val[v] === 'string') val[v] = val[v].trim(); |
| 22 | if (!val[v] || val[v] == 'None' || val[v] == '') { delete val[v]; } |
| 23 | } |
| 24 | } |
| 25 | function trimResults(val) |
| 26 | { |
| 27 | var i, x; |
| 28 | for (i = 0; i < val.length; ++i) |
| 29 | { |
| 30 | for (x in val[i]) |
| 31 | { |
| 32 | if (x.startsWith('_')) |
| 33 | { |
| 34 | delete val[i][x]; |
| 35 | } |
| 36 | else |
| 37 | { |
| 38 | if (val[i][x] == null || val[i][x] == 0) |
| 39 | { |
| 40 | delete val[i][x]; |
| 41 | } |
| 42 | } |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | function brief(headers, obj) |
| 47 | { |
| 48 | var i, x; |
| 49 | for (x = 0; x < obj.length; ++x) |
| 50 | { |
| 51 | for (i in obj[x]) |
| 52 | { |
| 53 | if (!headers.includes(i)) |
| 54 | { |
| 55 | delete obj[x][i]; |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | return (obj); |
| 60 | } |
| 61 | |
| 62 | function dataHandler(c) |
| 63 | { |
| 64 | this.str += c.toString(); |
| 65 | } |
| 66 | |
| 67 | function linux_identifiers() |
| 68 | { |
| 69 | var identifiers = {}; |
| 70 | var ret = {}; |
| 71 | var values = {}; |
| 72 | var child = null; |
| 73 | |
| 74 | if (!require('fs').existsSync('/sys/class/dmi/id')) { |
| 75 | if (require('fs').existsSync('/sys/firmware/devicetree/base/model')) { |
| 76 | if (require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim().startsWith('Raspberry')) { |
| 77 | identifiers['board_vendor'] = 'Raspberry Pi'; |
| 78 | identifiers['board_name'] = require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim(); |
| 79 | identifiers['board_serial'] = require('fs').readFileSync('/sys/firmware/devicetree/base/serial-number').toString().trim(); |
| 80 | const memorySlots = []; |
| 81 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 82 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 83 | child.stdin.write('vcgencmd get_mem arm && vcgencmd get_mem gpu\nexit\n'); |
| 84 | child.waitExit(); |
| 85 | try { |
| 86 | const lines = child.stdout.str.trim().split('\n'); |
| 87 | if (lines.length == 2) { |
| 88 | memorySlots.push({ Locator: "ARM Memory", Size: lines[0].split('=')[1].trim() }) |
| 89 | memorySlots.push({ Locator: "GPU Memory", Size: lines[1].split('=')[1].trim() }) |
| 90 | ret.memory = { Memory_Device: memorySlots }; |
| 91 | } |
| 92 | } catch (xx) { } |
| 93 | } else { |
| 94 | throw('Unknown board'); |
| 95 | } |
| 96 | } else { |
| 97 | throw ('this platform does not have DMI statistics'); |
| 98 | } |
| 99 | } else { |
| 100 | var entries = require('fs').readdirSync('/sys/class/dmi/id'); |
| 101 | for (var i in entries) { |
| 102 | if (require('fs').statSync('/sys/class/dmi/id/' + entries[i]).isFile()) { |
| 103 | try { |
| 104 | ret[entries[i]] = require('fs').readFileSync('/sys/class/dmi/id/' + entries[i]).toString().trim(); |
| 105 | } catch(z) { } |
| 106 | if (ret[entries[i]] == 'None') { delete ret[entries[i]]; } |
| 107 | } |
| 108 | } |
| 109 | entries = null; |
| 110 | |
| 111 | identifiers['bios_date'] = ret['bios_date']; |
| 112 | identifiers['bios_vendor'] = ret['bios_vendor']; |
| 113 | identifiers['bios_version'] = ret['bios_version']; |
| 114 | identifiers['bios_serial'] = ret['product_serial']; |
| 115 | identifiers['board_name'] = ret['board_name']; |
| 116 | identifiers['board_serial'] = ret['board_serial']; |
| 117 | identifiers['board_vendor'] = ret['board_vendor']; |
| 118 | identifiers['board_version'] = ret['board_version']; |
| 119 | identifiers['product_uuid'] = ret['product_uuid']; |
| 120 | identifiers['product_name'] = ret['product_name']; |
| 121 | } |
| 122 | |
| 123 | // BIOS Mode |
| 124 | try { |
| 125 | var uefiExist = false; |
| 126 | var assumePi = false; |
| 127 | |
| 128 | try { uefiExist = (require('fs')).existsSync('/sys/firmware/efi'); } |
| 129 | catch (ex) { uefiExist = false; } |
| 130 | |
| 131 | try { assumePi = (require('fs')).existsSync('/sys/firmware/devicetree/base/model'); } |
| 132 | catch (ex) { assumePi = false; } |
| 133 | |
| 134 | if (uefiExist) { |
| 135 | identifiers['bios_mode'] = 'UEFI'; |
| 136 | } else if (assumePi) { |
| 137 | var modelBuffer = (require('fs')).readFileSync('/sys/firmware/devicetree/base/model'); |
| 138 | var modelString = modelBuffer.toString().trim() |
| 139 | |
| 140 | if (modelString.includes('Raspberry Pi')) { |
| 141 | identifiers['bios_mode'] = 'Raspberry Pi Firmware (Proprietary)'; |
| 142 | } |
| 143 | } else { |
| 144 | identifiers['bios_mode'] = 'Legacy BIOS (MBR)'; |
| 145 | } |
| 146 | } catch (ex) { identifiers['bios_mode'] = 'Legacy / Unknown'; } |
| 147 | |
| 148 | // CPU Model info |
| 149 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 150 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 151 | child.stdin.write('cat /proc/cpuinfo | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n"); |
| 152 | child.waitExit(); |
| 153 | try { |
| 154 | identifiers['cpu_name'] = child.stdout.str.trim(); |
| 155 | if (identifiers['cpu_name'] == "") { // CPU BLANK, check lscpu instead |
| 156 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 157 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 158 | child.stdin.write('lscpu | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n"); |
| 159 | child.waitExit(); |
| 160 | try { identifiers['cpu_name'] = child.stdout.str.trim(); } catch (xx) { } |
| 161 | } |
| 162 | } catch (xx) { } |
| 163 | |
| 164 | // Kernel info |
| 165 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 166 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 167 | child.stdin.write('uname -r\nexit\n'); |
| 168 | child.waitExit(); |
| 169 | try { ret['kernel_release'] = child.stdout.str.trim(); } catch (xx) { } |
| 170 | |
| 171 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 172 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 173 | child.stdin.write('uname -v\nexit\n'); |
| 174 | child.waitExit(); |
| 175 | try { ret['kernel_build'] = child.stdout.str.trim(); } catch (xx) { } |
| 176 | |
| 177 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 178 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 179 | child.stdin.write('uname -m\nexit\n'); |
| 180 | child.waitExit(); |
| 181 | try { ret['arch'] = child.stdout.str.trim(); } catch (xx) { } |
| 182 | |
| 183 | // Fetch GPU info |
| 184 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 185 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 186 | child.stdin.write("lspci | grep ' VGA ' | tr '\\n' '`' | awk '{ a=split($0,lines" + ',"`"); printf "["; for(i=1;i<a;++i) { split(lines[i],gpu,"r: "); printf "%s\\"%s\\"", (i==1?"":","),gpu[2]; } printf "]"; }\'\nexit\n'); |
| 187 | child.waitExit(); |
| 188 | try { identifiers['gpu_name'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { } |
| 189 | |
| 190 | // Fetch Storage Info |
| 191 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 192 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 193 | child.stdin.write("lshw -class disk -disable network | tr '\\n' '`' | awk '" + '{ len=split($0,lines,"*"); printf "["; for(i=2;i<=len;++i) { model=""; caption=""; size=""; clen=split(lines[i],item,"`"); for(j=2;j<clen;++j) { split(item[j],tokens,":"); split(tokens[1],key," "); if(key[1]=="description") { caption=substr(tokens[2],2); } if(key[1]=="product") { model=substr(tokens[2],2); } if(key[1]=="size") { size=substr(tokens[2],2); } } if(model=="") { model=caption; } if(caption!="" || model!="") { printf "%s{\\"Caption\\":\\"%s\\",\\"Model\\":\\"%s\\",\\"Size\\":\\"%s\\"}",(i==2?"":","),caption,model,size; } } printf "]"; }\'\nexit\n'); |
| 194 | child.waitExit(); |
| 195 | try { identifiers['storage_devices'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { } |
| 196 | |
| 197 | // Fetch storage volumes using df |
| 198 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 199 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 200 | child.stdin.write('df -T -x tmpfs -x devtmpfs -x efivarfs | awk \'NR==1 || $1 ~ ".+"{print $3, $4, $5, $7, $2}\' | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $1, $2, $3, $4, $5}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n'); |
| 201 | child.waitExit(); |
| 202 | try { ret.volumes = JSON.parse(child.stdout.str.trim()); } catch (xx) { } |
| 203 | |
| 204 | values.identifiers = identifiers; |
| 205 | values.linux = ret; |
| 206 | trimIdentifiers(values.identifiers); |
| 207 | |
| 208 | var dmidecode = require('lib-finder').findBinary('dmidecode'); |
| 209 | if (dmidecode != null) |
| 210 | { |
| 211 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 212 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 213 | child.stderr.str = ''; child.stderr.on('data', dataHandler); |
| 214 | child.stdin.write(dmidecode + " -t memory | tr '\\n' '`' | "); |
| 215 | child.stdin.write(" awk '{ "); |
| 216 | child.stdin.write(' printf("[");'); |
| 217 | child.stdin.write(' comma="";'); |
| 218 | child.stdin.write(' c=split($0, lines, "``");'); |
| 219 | child.stdin.write(' for(i=1;i<=c;++i)'); |
| 220 | child.stdin.write(' {'); |
| 221 | child.stdin.write(' d=split(lines[i], val, "`");'); |
| 222 | child.stdin.write(' split(val[1], tokens, ",");'); |
| 223 | child.stdin.write(' split(tokens[2], dmitype, " ");'); |
| 224 | child.stdin.write(' dmi = dmitype[3]+0; '); |
| 225 | child.stdin.write(' if(dmi == 5 || dmi == 6 || dmi == 16 || dmi == 17)'); |
| 226 | child.stdin.write(' {'); |
| 227 | child.stdin.write(' ccx="";'); |
| 228 | child.stdin.write(' printf("%s{\\"%s\\": {", comma, val[2]);'); |
| 229 | child.stdin.write(' for(j=3;j<d;++j)'); |
| 230 | child.stdin.write(' {'); |
| 231 | child.stdin.write(' sub(/^[ \\t]*/,"",val[j]);'); |
| 232 | child.stdin.write(' if(split(val[j],tmp,":")>1)'); |
| 233 | child.stdin.write(' {'); |
| 234 | child.stdin.write(' sub(/^[ \\t]*/,"",tmp[2]);'); |
| 235 | child.stdin.write(' gsub(/ /,"",tmp[1]);'); |
| 236 | child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", ccx, tmp[1], tmp[2]);'); |
| 237 | child.stdin.write(' ccx=",";'); |
| 238 | child.stdin.write(' }'); |
| 239 | child.stdin.write(' }'); |
| 240 | child.stdin.write(' printf("}}");'); |
| 241 | child.stdin.write(' comma=",";'); |
| 242 | child.stdin.write(' }'); |
| 243 | child.stdin.write(' }'); |
| 244 | child.stdin.write(' printf("]");'); |
| 245 | child.stdin.write("}'\nexit\n"); |
| 246 | child.waitExit(); |
| 247 | |
| 248 | try |
| 249 | { |
| 250 | var j = JSON.parse(child.stdout.str); |
| 251 | var i, key, key2; |
| 252 | for (i = 0; i < j.length; ++i) |
| 253 | { |
| 254 | for (key in j[i]) |
| 255 | { |
| 256 | delete j[i][key]['ArrayHandle']; |
| 257 | delete j[i][key]['ErrorInformationHandle']; |
| 258 | for (key2 in j[i][key]) |
| 259 | { |
| 260 | if (j[i][key][key2] == 'Unknown' || j[i][key][key2] == 'Not Specified' || j[i][key][key2] == '') |
| 261 | { |
| 262 | delete j[i][key][key2]; |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | if(j.length > 0){ |
| 269 | var mem = {}; |
| 270 | for (i = 0; i < j.length; ++i) |
| 271 | { |
| 272 | for (key in j[i]) |
| 273 | { |
| 274 | if (mem[key] == null) { mem[key] = []; } |
| 275 | mem[key].push(j[i][key]); |
| 276 | } |
| 277 | } |
| 278 | values.linux.memory = mem; |
| 279 | } |
| 280 | } |
| 281 | catch (e) |
| 282 | { } |
| 283 | child = null; |
| 284 | } |
| 285 | |
| 286 | var usbdevices = require('lib-finder').findBinary('usb-devices'); |
| 287 | if (usbdevices != null) |
| 288 | { |
| 289 | var child = require('child_process').execFile('/bin/sh', ['sh']); |
| 290 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 291 | child.stderr.str = ''; child.stderr.on('data', dataHandler); |
| 292 | child.stdin.write(usbdevices + " | tr '\\n' '`' | "); |
| 293 | child.stdin.write(" awk '"); |
| 294 | child.stdin.write('{'); |
| 295 | child.stdin.write(' comma="";'); |
| 296 | child.stdin.write(' printf("[");'); |
| 297 | child.stdin.write(' len=split($0, group, "``");'); |
| 298 | child.stdin.write(' for(i=1;i<=len;++i)'); |
| 299 | child.stdin.write(' {'); |
| 300 | child.stdin.write(' comma2="";'); |
| 301 | child.stdin.write(' xlen=split(group[i], line, "`");'); |
| 302 | child.stdin.write(' scount=0;'); |
| 303 | child.stdin.write(' for(x=1;x<xlen;++x)'); |
| 304 | child.stdin.write(' {'); |
| 305 | child.stdin.write(' if(line[x] ~ "^S:")'); |
| 306 | child.stdin.write(' {'); |
| 307 | child.stdin.write(' ++scount;'); |
| 308 | child.stdin.write(' }'); |
| 309 | child.stdin.write(' }'); |
| 310 | child.stdin.write(' if(scount>0)'); |
| 311 | child.stdin.write(' {'); |
| 312 | child.stdin.write(' printf("%s{", comma); comma=",";'); |
| 313 | child.stdin.write(' for(x=1;x<xlen;++x)'); |
| 314 | child.stdin.write(' {'); |
| 315 | child.stdin.write(' if(line[x] ~ "^T:")'); |
| 316 | child.stdin.write(' {'); |
| 317 | child.stdin.write(' comma3="";'); |
| 318 | child.stdin.write(' printf("%s\\"hardware\\": {", comma2); comma2=",";'); |
| 319 | child.stdin.write(' sub(/^T:[ \\t]*/, "", line[x]);'); |
| 320 | child.stdin.write(' gsub(/= */, "=", line[x]);'); |
| 321 | child.stdin.write(' blen=split(line[x], tokens, " ");'); |
| 322 | child.stdin.write(' for(y=1;y<blen;++y)'); |
| 323 | child.stdin.write(' {'); |
| 324 | child.stdin.write(' match(tokens[y],/=/);'); |
| 325 | child.stdin.write(' h=substr(tokens[y],1,RSTART-1);'); |
| 326 | child.stdin.write(' v=substr(tokens[y],RSTART+1);'); |
| 327 | child.stdin.write(' sub(/#/, "", h);'); |
| 328 | child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", comma3, h, v); comma3=",";'); |
| 329 | child.stdin.write(' }'); |
| 330 | child.stdin.write(' printf("}");'); |
| 331 | child.stdin.write(' }'); |
| 332 | child.stdin.write(' if(line[x] ~ "^S:")'); |
| 333 | child.stdin.write(' {'); |
| 334 | child.stdin.write(' sub(/^S:[ \\t]*/, "", line[x]);'); |
| 335 | child.stdin.write(' match(line[x], /=/);'); |
| 336 | child.stdin.write(' h=substr(line[x],1,RSTART-1);'); |
| 337 | child.stdin.write(' v=substr(line[x],RSTART+1);'); |
| 338 | child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", comma2, h,v); comma2=",";'); |
| 339 | child.stdin.write(' }'); |
| 340 | child.stdin.write(' }'); |
| 341 | child.stdin.write(' printf("}");'); |
| 342 | child.stdin.write(' }'); |
| 343 | child.stdin.write(' }'); |
| 344 | child.stdin.write(' printf("]");'); |
| 345 | child.stdin.write("}'\nexit\n"); |
| 346 | child.waitExit(); |
| 347 | |
| 348 | try |
| 349 | { |
| 350 | values.linux.usb = JSON.parse(child.stdout.str); |
| 351 | } |
| 352 | catch(x) |
| 353 | { } |
| 354 | child = null; |
| 355 | } |
| 356 | |
| 357 | var pcidevices = require('lib-finder').findBinary('lspci'); |
| 358 | if (pcidevices != null) |
| 359 | { |
| 360 | var child = require('child_process').execFile('/bin/sh', ['sh']); |
| 361 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 362 | child.stderr.str = ''; child.stderr.on('data', dataHandler); |
| 363 | child.stdin.write(pcidevices + " -m | tr '\\n' '`' | "); |
| 364 | child.stdin.write(" awk '"); |
| 365 | child.stdin.write('{'); |
| 366 | child.stdin.write(' printf("[");'); |
| 367 | child.stdin.write(' comma="";'); |
| 368 | child.stdin.write(' alen=split($0, lines, "`");'); |
| 369 | child.stdin.write(' for(a=1;a<alen;++a)'); |
| 370 | child.stdin.write(' {'); |
| 371 | child.stdin.write(' match(lines[a], / /);'); |
| 372 | child.stdin.write(' blen=split(lines[a], meta, "\\"");'); |
| 373 | child.stdin.write(' bus=substr(lines[a], 1, RSTART);'); |
| 374 | child.stdin.write(' gsub(/ /, "", bus);'); |
| 375 | child.stdin.write(' printf("%s{\\"bus\\": \\"%s\\"", comma, bus); comma=",";'); |
| 376 | child.stdin.write(' printf(", \\"device\\": \\"%s\\"", meta[2]);'); |
| 377 | child.stdin.write(' printf(", \\"manufacturer\\": \\"%s\\"", meta[4]);'); |
| 378 | child.stdin.write(' printf(", \\"description\\": \\"%s\\"", meta[6]);'); |
| 379 | child.stdin.write(' if(meta[8] != "")'); |
| 380 | child.stdin.write(' {'); |
| 381 | child.stdin.write(' printf(", \\"subsystem\\": {");'); |
| 382 | child.stdin.write(' printf("\\"manufacturer\\": \\"%s\\"", meta[8]);'); |
| 383 | child.stdin.write(' printf(", \\"description\\": \\"%s\\"", meta[10]);'); |
| 384 | child.stdin.write(' printf("}");'); |
| 385 | child.stdin.write(' }'); |
| 386 | child.stdin.write(' printf("}");'); |
| 387 | child.stdin.write(' }'); |
| 388 | child.stdin.write(' printf("]");'); |
| 389 | child.stdin.write("}'\nexit\n"); |
| 390 | child.waitExit(); |
| 391 | |
| 392 | try |
| 393 | { |
| 394 | values.linux.pci = JSON.parse(child.stdout.str); |
| 395 | } |
| 396 | catch (x) |
| 397 | { } |
| 398 | child = null; |
| 399 | } |
| 400 | |
| 401 | // Linux Last Boot Up Time |
| 402 | try { |
| 403 | child = require('child_process').execFile('/usr/bin/uptime', ['', '-s']); // must include blank value at begining for some reason? |
| 404 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 405 | child.stderr.on('data', function () { }); |
| 406 | child.waitExit(); |
| 407 | var regex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/; |
| 408 | if (regex.test(child.stdout.str.trim())) { |
| 409 | values.linux.LastBootUpTime = child.stdout.str.trim(); |
| 410 | } else { |
| 411 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 412 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 413 | child.stdin.write('date -d "@$(( $(date +%s) - $(awk \'{print int($1)}\' /proc/uptime) ))" "+%Y-%m-%d %H:%M:%S"\nexit\n'); |
| 414 | child.waitExit(); |
| 415 | if (regex.test(child.stdout.str.trim())) { |
| 416 | values.linux.LastBootUpTime = child.stdout.str.trim(); |
| 417 | } |
| 418 | } |
| 419 | child = null; |
| 420 | } catch (ex) { } |
| 421 | |
| 422 | // Linux TPM |
| 423 | try { |
| 424 | if (require('fs').statSync('/sys/class/tpm/tpm0').isDirectory()){ |
| 425 | values.tpm = { |
| 426 | SpecVersion: require('fs').readFileSync('/sys/class/tpm/tpm0/tpm_version_major').toString().trim() |
| 427 | } |
| 428 | } |
| 429 | } catch (ex) { } |
| 430 | |
| 431 | // Linux Batteries |
| 432 | try { |
| 433 | var batteries = require('fs').readdirSync('/sys/class/power_supply/'); |
| 434 | if (batteries.length != 0) { |
| 435 | values.battery = []; |
| 436 | for (var i in batteries) { |
| 437 | const filesToRead = [ |
| 438 | 'capacity', 'cycle_count', 'energy_full', 'energy_full_design', |
| 439 | 'energy_now', 'manufacturer', 'model_name', 'power_now', |
| 440 | 'serial_number', 'status', 'technology', 'voltage_now' |
| 441 | ]; |
| 442 | const thedata = {}; |
| 443 | for (var x in filesToRead) { |
| 444 | try { |
| 445 | const content = require('fs').readFileSync('/sys/class/power_supply/' + batteries[i] + '/' + filesToRead[x]).toString().trim(); |
| 446 | thedata[filesToRead[x]] = /^\d+$/.test(content) ? parseInt(content, 10) : content; |
| 447 | } catch (err) { } |
| 448 | } |
| 449 | if (Object.keys(thedata).length === 0) continue; // No data read, skip |
| 450 | const status = (thedata.status || '').toLowerCase(); |
| 451 | const isCharging = status === 'charging'; |
| 452 | const isDischarging = status === 'discharging'; |
| 453 | const toMilli = function (val) { return Math.round((val || 0) / 1000) }; // Convert from µ units to m units (divide by 1000) |
| 454 | const batteryJson = { |
| 455 | "InstanceName": batteries[i], |
| 456 | "CycleCount": thedata.cycle_count || 0, |
| 457 | "FullChargedCapacity": toMilli(thedata.energy_full), |
| 458 | "Chemistry": (thedata.technology || ''), |
| 459 | "DesignedCapacity": toMilli(thedata.energy_full_design), |
| 460 | "DeviceName": thedata.model_name || "Battery", |
| 461 | "ManufactureName": thedata.manufacturer || "Unknown", |
| 462 | "SerialNumber": thedata.serial_number || "unknown", |
| 463 | "ChargeRate": isCharging ? toMilli(thedata.power_now) : 0, |
| 464 | "Charging": isCharging, |
| 465 | "DischargeRate": isDischarging ? toMilli(thedata.power_now) : 0, |
| 466 | "Discharging": isDischarging, |
| 467 | "RemainingCapacity": toMilli(thedata.energy_now), |
| 468 | "Voltage": toMilli(thedata.voltage_now), |
| 469 | "Health": (thedata.energy_full && thedata.energy_full_design ? Math.floor((thedata.energy_full / thedata.energy_full_design) * 100) : 0), |
| 470 | "BatteryCharge": (thedata.energy_now && thedata.energy_full ? Math.floor((thedata.energy_now / thedata.energy_full) * 100) : (thedata.capacity ? thedata.capacity : 0)) |
| 471 | }; |
| 472 | values.battery.push(batteryJson); |
| 473 | } |
| 474 | if (values.battery.length == 0) { delete values.battery; } |
| 475 | } |
| 476 | } catch (ex) { } |
| 477 | |
| 478 | return (values); |
| 479 | } |
| 480 | |
| 481 | function windows_wmic_results(str) |
| 482 | { |
| 483 | var lines = str.trim().split('\r\n'); |
| 484 | var keys = lines[0].split(','); |
| 485 | var i, key, keyval; |
| 486 | var tokens; |
| 487 | var result = []; |
| 488 | |
| 489 | console.log('Lines: ' + lines.length, 'Keys: ' + keys.length); |
| 490 | |
| 491 | for (i = 1; i < lines.length; ++i) |
| 492 | { |
| 493 | var obj = {}; |
| 494 | console.log('i: ' + i); |
| 495 | tokens = lines[i].split(','); |
| 496 | for (key = 0; key < keys.length; ++key) |
| 497 | { |
| 498 | var tmp = Buffer.from(tokens[key], 'binary').toString(); |
| 499 | console.log(tokens[key], tmp); |
| 500 | tokens[key] = tmp == null ? '' : tmp; |
| 501 | if (tokens[key].trim()) |
| 502 | { |
| 503 | obj[keys[key].trim()] = tokens[key].trim(); |
| 504 | } |
| 505 | } |
| 506 | delete obj.Node; |
| 507 | result.push(obj); |
| 508 | } |
| 509 | return (result); |
| 510 | } |
| 511 | |
| 512 | function windows_identifiers() |
| 513 | { |
| 514 | var ret = { windows: {} }; |
| 515 | var items, item, i; |
| 516 | |
| 517 | ret['identifiers'] = {}; |
| 518 | |
| 519 | var values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_Bios", ['ReleaseDate', 'Manufacturer', 'SMBIOSBIOSVersion', 'SerialNumber']); |
| 520 | if(values[0]){ |
| 521 | ret['identifiers']['bios_date'] = values[0]['ReleaseDate']; |
| 522 | ret['identifiers']['bios_vendor'] = values[0]['Manufacturer']; |
| 523 | ret['identifiers']['bios_version'] = values[0]['SMBIOSBIOSVersion']; |
| 524 | ret['identifiers']['bios_serial'] = values[0]['SerialNumber']; |
| 525 | } |
| 526 | ret['identifiers']['bios_mode'] = 'Legacy'; |
| 527 | |
| 528 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_BaseBoard", ['Product', 'SerialNumber', 'Manufacturer', 'Version']); |
| 529 | if(values[0]){ |
| 530 | ret['identifiers']['board_name'] = values[0]['Product']; |
| 531 | ret['identifiers']['board_serial'] = values[0]['SerialNumber']; |
| 532 | ret['identifiers']['board_vendor'] = values[0]['Manufacturer']; |
| 533 | ret['identifiers']['board_version'] = values[0]['Version']; |
| 534 | } |
| 535 | |
| 536 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_ComputerSystemProduct", ['UUID', 'Name']); |
| 537 | if(values[0]){ |
| 538 | ret['identifiers']['product_uuid'] = values[0]['UUID']; |
| 539 | ret['identifiers']['product_name'] = values[0]['Name']; |
| 540 | } |
| 541 | |
| 542 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_SystemEnclosure", ['SerialNumber', 'SMBIOSAssetTag', 'Manufacturer']); |
| 543 | if(values[0]){ |
| 544 | ret['identifiers']['chassis_serial'] = values[0]['SerialNumber']; |
| 545 | ret['identifiers']['chassis_assettag'] = values[0]['SMBIOSAssetTag']; |
| 546 | ret['identifiers']['chassis_manufacturer'] = values[0]['Manufacturer']; |
| 547 | } |
| 548 | |
| 549 | trimIdentifiers(ret.identifiers); |
| 550 | |
| 551 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_PhysicalMemory"); |
| 552 | if(values[0]){ |
| 553 | trimResults(values); |
| 554 | ret.windows.memory = values; |
| 555 | } |
| 556 | |
| 557 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_OperatingSystem"); |
| 558 | if(values[0]){ |
| 559 | trimResults(values); |
| 560 | ret.windows.osinfo = values[0]; |
| 561 | |
| 562 | try { |
| 563 | var reg = require('win-registry'); |
| 564 | var ubr = reg.QueryKey(reg.HKEY.LocalMachine, 'Software\\Microsoft\\Windows NT\\CurrentVersion', 'UBR'); |
| 565 | if(ubr && ret.windows.osinfo.Version){ |
| 566 | ret.windows.osinfo.BuildRevision = ret.windows.osinfo.Version + "." + ubr |
| 567 | } |
| 568 | } catch (ex){} |
| 569 | } |
| 570 | |
| 571 | values = require('win-wmi-fixed').query('ROOT\\CIMV2', "SELECT * FROM Win32_DiskPartition"); |
| 572 | if(values[0]){ |
| 573 | trimResults(values); |
| 574 | ret.windows.partitions = values; |
| 575 | for (var i in values) { |
| 576 | if (values[i].Type=='GPT: System') { |
| 577 | ret['identifiers']['bios_mode'] = 'UEFI'; |
| 578 | } |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_Processor", ['Caption', 'DeviceID', 'Manufacturer', 'MaxClockSpeed', 'Name', 'SocketDesignation']); |
| 583 | if(values[0]){ |
| 584 | ret.windows.cpu = values; |
| 585 | } |
| 586 | |
| 587 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_VideoController", ['Name', 'CurrentHorizontalResolution', 'CurrentVerticalResolution']); |
| 588 | if(values[0]){ |
| 589 | ret.windows.gpu = values; |
| 590 | } |
| 591 | |
| 592 | values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_DiskDrive", ['Caption', 'DeviceID', 'Model', 'Partitions', 'Size', 'Status']); |
| 593 | if(values[0]){ |
| 594 | ret.windows.drives = values; |
| 595 | } |
| 596 | |
| 597 | // Insert GPU names |
| 598 | ret.identifiers.gpu_name = []; |
| 599 | for (var gpuinfo in ret.windows.gpu) |
| 600 | { |
| 601 | if (ret.windows.gpu[gpuinfo].Name) { ret.identifiers.gpu_name.push(ret.windows.gpu[gpuinfo].Name); } |
| 602 | } |
| 603 | |
| 604 | // Insert Storage Devices |
| 605 | ret.identifiers.storage_devices = []; |
| 606 | for (var dv in ret.windows.drives) |
| 607 | { |
| 608 | ret.identifiers.storage_devices.push({ Caption: ret.windows.drives[dv].Caption, Model: ret.windows.drives[dv].Model, Size: ret.windows.drives[dv].Size }); |
| 609 | } |
| 610 | |
| 611 | try { ret.identifiers.cpu_name = ret.windows.cpu[0].Name; } catch (x) { } |
| 612 | |
| 613 | // Windows TPM |
| 614 | IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }; |
| 615 | try { |
| 616 | values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftTpm', "SELECT * FROM Win32_Tpm", ['IsActivated_InitialValue','IsEnabled_InitialValue','IsOwned_InitialValue','ManufacturerId','ManufacturerVersion','SpecVersion']); |
| 617 | if(values[0]) { |
| 618 | ret.tpm = { |
| 619 | SpecVersion: values[0].SpecVersion.split(",")[0], |
| 620 | ManufacturerId: IntToStr(values[0].ManufacturerId).replace(/[^\x00-\x7F]/g, ""), |
| 621 | ManufacturerVersion: values[0].ManufacturerVersion, |
| 622 | IsActivated: values[0].IsActivated_InitialValue, |
| 623 | IsEnabled: values[0].IsEnabled_InitialValue, |
| 624 | IsOwned: values[0].IsOwned_InitialValue, |
| 625 | } |
| 626 | } |
| 627 | } catch (ex) { } |
| 628 | |
| 629 | // Windows Batteries |
| 630 | IntToStrLE = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }; |
| 631 | try { |
| 632 | function mergeJSONArrays() { |
| 633 | var resultMap = {}; |
| 634 | var result = []; |
| 635 | // Loop through all arguments (arrays) |
| 636 | for (var i = 0; i < arguments.length; i++) { |
| 637 | var currentArray = arguments[i]; |
| 638 | // Skip if not an array |
| 639 | if (!currentArray || currentArray.constructor !== Array) { |
| 640 | continue; |
| 641 | } |
| 642 | // Process each object in the array |
| 643 | for (var j = 0; j < currentArray.length; j++) { |
| 644 | var obj = currentArray[j]; |
| 645 | // Skip if not an object or missing InstanceName |
| 646 | if (!obj || typeof obj !== 'object' || !obj.InstanceName) { |
| 647 | continue; |
| 648 | } |
| 649 | var name = obj.InstanceName; |
| 650 | // Create new entry if it doesn't exist |
| 651 | if (!resultMap[name]) { |
| 652 | resultMap[name] = { InstanceName: name }; |
| 653 | result.push(resultMap[name]); |
| 654 | } |
| 655 | // Copy all properties except InstanceName |
| 656 | for (var key in obj) { |
| 657 | if (obj.hasOwnProperty(key) && key !== 'InstanceName') { |
| 658 | resultMap[name][key] = obj[key]; |
| 659 | } |
| 660 | } |
| 661 | } |
| 662 | } |
| 663 | return result; |
| 664 | } |
| 665 | values = require('win-wmi').query('ROOT\\WMI', "SELECT * FROM BatteryCycleCount",['InstanceName','CycleCount']); |
| 666 | var values2 = require('win-wmi').query('ROOT\\WMI', "SELECT * FROM BatteryFullChargedCapacity",['InstanceName','FullChargedCapacity']); |
| 667 | var values3 = require('win-wmi').query('ROOT\\WMI', "SELECT * FROM BatteryRuntime",['InstanceName','EstimatedRuntime']); |
| 668 | var values4 = require('win-wmi').query('ROOT\\WMI', "SELECT * FROM BatteryStaticData",['InstanceName','Chemistry','DesignedCapacity','DeviceName','ManufactureDate','ManufactureName','SerialNumber']); |
| 669 | for (i = 0; i < values4.length; ++i) { |
| 670 | if (values4[i].Chemistry) { values4[i].Chemistry = IntToStrLE(parseInt(values4[i].Chemistry)); } |
| 671 | if (values4[i].ManufactureDate) { if (values4[i].ManufactureDate.indexOf('*****') != -1) delete values4[i].ManufactureDate; } |
| 672 | } |
| 673 | var values5 = require('win-wmi').query('ROOT\\WMI', "SELECT * FROM BatteryStatus",['InstanceName','ChargeRate','Charging','DischargeRate','Discharging','RemainingCapacity','Voltage']); |
| 674 | var values6 = []; |
| 675 | if (values2.length > 0 && values4.length > 0) { |
| 676 | for (i = 0; i < values2.length; ++i) { |
| 677 | for (var j = 0; j < values4.length; ++j) { |
| 678 | if (values2[i].InstanceName == values4[j].InstanceName) { |
| 679 | if ((values4[j].DesignedCapacity && values4[j].DesignedCapacity > 0) && (values2[i].FullChargedCapacity && values2[i].FullChargedCapacity > 0)) { |
| 680 | values6[i] = { |
| 681 | Health: Math.floor((values2[i].FullChargedCapacity / values4[j].DesignedCapacity) * 100), |
| 682 | InstanceName: values2[i].InstanceName |
| 683 | }; |
| 684 | if (values6[i].Health > 100) { values6[i].Health = 100; } |
| 685 | } else { |
| 686 | values6[i] = { Health: 0, InstanceName: values2[i].InstanceName }; |
| 687 | } |
| 688 | break; |
| 689 | } |
| 690 | } |
| 691 | } |
| 692 | } |
| 693 | var values7 = []; |
| 694 | if (values2.length > 0 && values5.length > 0) { |
| 695 | for (i = 0; i < values2.length; ++i) { |
| 696 | for (var j = 0; j < values5.length; ++j) { |
| 697 | if (values2[i].InstanceName == values5[j].InstanceName) { |
| 698 | if ((values2[i].FullChargedCapacity && values2[i].FullChargedCapacity > 0) && (values5[j].RemainingCapacity && values5[j].RemainingCapacity > 0)) { |
| 699 | values7[i] = { |
| 700 | BatteryCharge: Math.floor((values5[j].RemainingCapacity / values2[i].FullChargedCapacity) * 100), |
| 701 | InstanceName: values2[i].InstanceName |
| 702 | }; |
| 703 | } else { |
| 704 | values7[i] = { BatteryCharge: 0, InstanceName: values2[i].InstanceName }; |
| 705 | } |
| 706 | break; |
| 707 | } |
| 708 | } |
| 709 | } |
| 710 | } |
| 711 | ret.battery = mergeJSONArrays(values, values2, values3, values4, values5, values6, values7); |
| 712 | } catch (ex) { } |
| 713 | |
| 714 | return (ret); |
| 715 | } |
| 716 | function macos_identifiers() |
| 717 | { |
| 718 | var ret = { identifiers: {}, darwin: {} }; |
| 719 | var child; |
| 720 | |
| 721 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 722 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 723 | child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep board-id | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); |
| 724 | child.waitExit(); |
| 725 | ret.identifiers.board_name = child.stdout.str.trim(); |
| 726 | |
| 727 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 728 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 729 | child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformSerialNumber | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); |
| 730 | child.waitExit(); |
| 731 | ret.identifiers.board_serial = child.stdout.str.trim(); |
| 732 | |
| 733 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 734 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 735 | child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep manufacturer | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); |
| 736 | child.waitExit(); |
| 737 | ret.identifiers.board_vendor = child.stdout.str.trim(); |
| 738 | |
| 739 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 740 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 741 | child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep version | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); |
| 742 | child.waitExit(); |
| 743 | ret.identifiers.board_version = child.stdout.str.trim(); |
| 744 | |
| 745 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 746 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 747 | child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformUUID | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); |
| 748 | child.waitExit(); |
| 749 | ret.identifiers.product_uuid = child.stdout.str.trim(); |
| 750 | |
| 751 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 752 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 753 | child.stdin.write('sysctl -n machdep.cpu.brand_string\nexit\n'); |
| 754 | child.waitExit(); |
| 755 | ret.identifiers.cpu_name = child.stdout.str.trim(); |
| 756 | |
| 757 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 758 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 759 | child.stdin.write('system_profiler SPMemoryDataType\nexit\n'); |
| 760 | child.waitExit(); |
| 761 | var lines = child.stdout.str.trim().split('\n'); |
| 762 | if(lines.length > 0) { |
| 763 | const memorySlots = []; |
| 764 | if(lines[2].trim().includes('Memory Slots:')) { // OLD MACS WITH SLOTS |
| 765 | var memorySlots1 = child.stdout.str.split(/\n{2,}/).slice(3); |
| 766 | memorySlots1.forEach(function(slot,index) { |
| 767 | var lines = slot.split('\n'); |
| 768 | if(lines.length == 1){ // start here |
| 769 | if(lines[0].trim()!=''){ |
| 770 | var slotObj = { DeviceLocator: lines[0].trim().replace(/:$/, '') }; // Initialize name as an empty string |
| 771 | var nextline = memorySlots1[index+1].split('\n'); |
| 772 | nextline.forEach(function(line) { |
| 773 | if (line.trim() !== '') { |
| 774 | var parts = line.split(':'); |
| 775 | var key = parts[0].trim(); |
| 776 | var value = parts[1].trim(); |
| 777 | value = (key == 'Part Number' || key == 'Manufacturer') ? hexToAscii(parts[1].trim()) : parts[1].trim(); |
| 778 | slotObj[key.replace(' ','')] = value; // Store attribute in the slot object |
| 779 | } |
| 780 | }); |
| 781 | memorySlots.push(slotObj); |
| 782 | } |
| 783 | } |
| 784 | }); |
| 785 | } else { // NEW MACS WITHOUT SLOTS |
| 786 | memorySlots.push({ DeviceLocator: "Onboard Memory", Size: lines[2].split(":")[1].trim(), PartNumber: lines[3].split(":")[1].trim(), Manufacturer: lines[4].split(":")[1].trim() }) |
| 787 | } |
| 788 | ret.darwin.memory = memorySlots; |
| 789 | } |
| 790 | |
| 791 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 792 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 793 | child.stdin.write('diskutil info -all\nexit\n'); |
| 794 | child.waitExit(); |
| 795 | var sections = child.stdout.str.split('**********\n'); |
| 796 | if(sections.length > 0){ |
| 797 | var devices = []; |
| 798 | for (var i = 0; i < sections.length; i++) { |
| 799 | var lines = sections[i].split('\n'); |
| 800 | var deviceInfo = {}; |
| 801 | var wholeYes = false; |
| 802 | var physicalYes = false; |
| 803 | var oldmac = false; |
| 804 | for (var j = 0; j < lines.length; j++) { |
| 805 | var keyValue = lines[j].split(':'); |
| 806 | var key = keyValue[0].trim(); |
| 807 | var value = keyValue[1] ? keyValue[1].trim() : ''; |
| 808 | if (key === 'Virtual') oldmac = true; |
| 809 | if (key === 'Whole' && value === 'Yes') wholeYes = true; |
| 810 | if (key === 'Virtual' && value === 'No') physicalYes = true; |
| 811 | if(value && key === 'Device / Media Name'){ |
| 812 | deviceInfo['Caption'] = value; |
| 813 | } |
| 814 | if(value && key === 'Disk Size'){ |
| 815 | deviceInfo['Size'] = value.split(' ')[0] + ' ' + value.split(' ')[1]; |
| 816 | } |
| 817 | } |
| 818 | if (wholeYes) { |
| 819 | if (oldmac) { |
| 820 | if (physicalYes) devices.push(deviceInfo); |
| 821 | } else { |
| 822 | devices.push(deviceInfo); |
| 823 | } |
| 824 | } |
| 825 | } |
| 826 | ret.identifiers.storage_devices = devices; |
| 827 | } |
| 828 | |
| 829 | // Fetch storage volumes using df |
| 830 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 831 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 832 | child.stdin.write('df -aHY | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $3, $4, $5, $10, $2}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n'); |
| 833 | child.waitExit(); |
| 834 | try { |
| 835 | ret.darwin.volumes = JSON.parse(child.stdout.str.trim()); |
| 836 | for (var index = 0; index < ret.darwin.volumes.length; index++) { |
| 837 | if (ret.darwin.volumes[index].type == 'auto_home'){ |
| 838 | ret.darwin.volumes.splice(index,1); |
| 839 | } |
| 840 | } |
| 841 | if (ret.darwin.volumes.length == 0) { // not sonima OS so dont show type for now |
| 842 | child = require('child_process').execFile('/bin/sh', ['sh']); |
| 843 | child.stdout.str = ''; child.stdout.on('data', dataHandler); |
| 844 | child.stdin.write('df -aH | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\"},", $2, $3, $4, $9}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n'); |
| 845 | child.waitExit(); |
| 846 | try { |
| 847 | ret.darwin.volumes = JSON.parse(child.stdout.str.trim()); |
| 848 | for (var index = 0; index < ret.darwin.volumes.length; index++) { |
| 849 | if (ret.darwin.volumes[index].size == 'auto_home'){ |
| 850 | ret.darwin.volumes.splice(index,1); |
| 851 | } |
| 852 | } |
| 853 | } catch (xx) { } |
| 854 | } |
| 855 | } catch (xx) { } |
| 856 | child = null; |
| 857 | |
| 858 | // MacOS Last Boot Up Time |
| 859 | try { |
| 860 | child = require('child_process').execFile('/usr/sbin/sysctl', ['', 'kern.boottime']); // must include blank value at begining for some reason? |
| 861 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 862 | child.stderr.on('data', function () { }); |
| 863 | child.waitExit(); |
| 864 | const timestampMatch = /\{ sec = (\d+), usec = \d+ \}/.exec(child.stdout.str.trim()); |
| 865 | if (!ret.darwin) { |
| 866 | ret.darwin = { LastBootUpTime: parseInt(timestampMatch[1]) }; |
| 867 | } else { |
| 868 | ret.darwin.LastBootUpTime = parseInt(timestampMatch[1]); |
| 869 | } |
| 870 | child = null; |
| 871 | } catch (ex) { } |
| 872 | |
| 873 | trimIdentifiers(ret.identifiers); |
| 874 | |
| 875 | child = null; |
| 876 | return (ret); |
| 877 | } |
| 878 | |
| 879 | function hexToAscii(hexString) { |
| 880 | if(!hexString.startsWith('0x')) return hexString.trim(); |
| 881 | hexString = hexString.startsWith('0x') ? hexString.slice(2) : hexString; |
| 882 | var str = ''; |
| 883 | for (var i = 0; i < hexString.length; i += 2) { |
| 884 | var hexPair = hexString.substr(i, 2); |
| 885 | str += String.fromCharCode(parseInt(hexPair, 16)); |
| 886 | } |
| 887 | str = str.replace(/[\u007F-\uFFFF]/g, ''); // Remove characters from 0x0080 to 0xFFFF |
| 888 | return str.trim(); |
| 889 | } |
| 890 | |
| 891 | function win_chassisType() |
| 892 | { |
| 893 | // use new win-wmi-fixed module to get arrays correctly for time being |
| 894 | try { |
| 895 | var tokens = require('win-wmi-fixed').query('ROOT\\CIMV2', 'SELECT ChassisTypes FROM Win32_SystemEnclosure', ['ChassisTypes']); |
| 896 | if (tokens[0]) { |
| 897 | return (parseInt(tokens[0]['ChassisTypes'][0])); |
| 898 | } |
| 899 | } catch (e) { |
| 900 | return (2); // unknown |
| 901 | } |
| 902 | } |
| 903 | |
| 904 | function win_systemType() |
| 905 | { |
| 906 | try { |
| 907 | var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT PCSystemType FROM Win32_ComputerSystem', ['PCSystemType']); |
| 908 | if (tokens[0]) { |
| 909 | return (parseInt(tokens[0]['PCSystemType'])); |
| 910 | } else { |
| 911 | return (parseInt(1)); // default is desktop |
| 912 | } |
| 913 | } catch (ex) { |
| 914 | return (parseInt(1)); // default is desktop |
| 915 | } |
| 916 | |
| 917 | } |
| 918 | |
| 919 | function win_formFactor(chassistype) |
| 920 | { |
| 921 | var ret = 'DESKTOP'; |
| 922 | switch (chassistype) |
| 923 | { |
| 924 | case 11: // Handheld |
| 925 | case 30: // Tablet |
| 926 | case 31: // Convertible |
| 927 | case 32: // Detachable |
| 928 | ret = 'TABLET'; |
| 929 | break; |
| 930 | case 9: // Laptop |
| 931 | case 10: // Notebook |
| 932 | case 14: // Sub Notebook |
| 933 | ret = 'LAPTOP'; |
| 934 | break; |
| 935 | default: |
| 936 | ret = win_systemType() == 2 ? 'MOBILE' : 'DESKTOP'; |
| 937 | break; |
| 938 | } |
| 939 | |
| 940 | return (ret); |
| 941 | } |
| 942 | |
| 943 | switch(process.platform) |
| 944 | { |
| 945 | case 'linux': |
| 946 | module.exports = { _ObjectID: 'identifiers', get: linux_identifiers }; |
| 947 | break; |
| 948 | case 'win32': |
| 949 | module.exports = { _ObjectID: 'identifiers', get: windows_identifiers, chassisType: win_chassisType, formFactor: win_formFactor, systemType: win_systemType }; |
| 950 | break; |
| 951 | case 'darwin': |
| 952 | module.exports = { _ObjectID: 'identifiers', get: macos_identifiers }; |
| 953 | break; |
| 954 | default: |
| 955 | module.exports = { get: function () { throw ('Unsupported Platform'); } }; |
| 956 | break; |
| 957 | } |
| 958 | module.exports.isDocker = function isDocker() |
| 959 | { |
| 960 | if (process.platform != 'linux') { return (false); } |
| 961 | |
| 962 | var child = require('child_process').execFile('/bin/sh', ['sh']); |
| 963 | child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 964 | child.stdin.write("cat /proc/self/cgroup | tr '\n' '`' | awk -F'`' '{ split($1, res, " + '"/"); if(res[2]=="docker"){print "1";} }\'\nexit\n'); |
| 965 | child.waitExit(); |
| 966 | return (child.stdout.str != ''); |
| 967 | }; |
| 968 | module.exports.isBatteryPowered = function isBatteryOperated() |
| 969 | { |
| 970 | var ret = false; |
| 971 | switch(process.platform) |
| 972 | { |
| 973 | default: |
| 974 | break; |
| 975 | case 'linux': |
| 976 | var devices = require('fs').readdirSync('/sys/class/power_supply'); |
| 977 | for (var i in devices) |
| 978 | { |
| 979 | if (require('fs').readFileSync('/sys/class/power_supply/' + devices[i] + '/type').toString().trim() == 'Battery') |
| 980 | { |
| 981 | ret = true; |
| 982 | break; |
| 983 | } |
| 984 | } |
| 985 | break; |
| 986 | case 'win32': |
| 987 | var GM = require('_GenericMarshal'); |
| 988 | var stats = GM.CreateVariable(12); |
| 989 | var kernel32 = GM.CreateNativeProxy('Kernel32.dll'); |
| 990 | kernel32.CreateMethod('GetSystemPowerStatus'); |
| 991 | if (kernel32.GetSystemPowerStatus(stats).Val != 0) |
| 992 | { |
| 993 | if(stats.toBuffer()[1] != 128 && stats.toBuffer()[1] != 255) |
| 994 | { |
| 995 | ret = true; |
| 996 | } |
| 997 | else |
| 998 | { |
| 999 | // No Battery detected, so lets check if there is supposed to be one |
| 1000 | var formFactor = win_formFactor(win_chassisType()); |
| 1001 | return (formFactor == 'LAPTOP' || formFactor == 'TABLET' || formFactor == 'MOBILE'); |
| 1002 | } |
| 1003 | } |
| 1004 | break; |
| 1005 | case 'darwin': |
| 1006 | var child = require('child_process').execFile('/bin/sh', ['sh']); |
| 1007 | child.stdout.str = ''; child.stdout.on('data', function(c){ this.str += c.toString(); }); |
| 1008 | child.stderr.str = ''; child.stderr.on('data', function(c){ this.str += c.toString(); }); |
| 1009 | child.stdin.write("pmset -g batt | tr '\\n' '`' | awk -F'`' '{ if(NF>2) { print \"true\"; }}'\nexit\n"); |
| 1010 | child.waitExit(); |
| 1011 | if(child.stdout.str.trim() != '') { ret = true; } |
| 1012 | break; |
| 1013 | } |
| 1014 | return (ret); |
| 1015 | }; |
| 1016 | module.exports.isVM = function isVM() |
| 1017 | { |
| 1018 | var ret = false; |
| 1019 | var id = this.get(); |
| 1020 | if (id.linux && id.linux.sys_vendor) |
| 1021 | { |
| 1022 | switch (id.linux.sys_vendor) |
| 1023 | { |
| 1024 | case 'VMware, Inc.': |
| 1025 | case 'QEMU': |
| 1026 | case 'Xen': |
| 1027 | ret = true; |
| 1028 | break; |
| 1029 | default: |
| 1030 | break; |
| 1031 | } |
| 1032 | } |
| 1033 | if (id.identifiers.bios_vendor) |
| 1034 | { |
| 1035 | switch(id.identifiers.bios_vendor) |
| 1036 | { |
| 1037 | case 'VMware, Inc.': |
| 1038 | case 'Xen': |
| 1039 | case 'SeaBIOS': |
| 1040 | case 'EFI Development Kit II / OVMF': |
| 1041 | case 'Proxmox distribution of EDK II': |
| 1042 | ret = true; |
| 1043 | break; |
| 1044 | default: |
| 1045 | break; |
| 1046 | } |
| 1047 | } |
| 1048 | if (id.identifiers.board_vendor && id.identifiers.board_vendor == 'VMware, Inc.') { ret = true; } |
| 1049 | if (id.identifiers.board_name) |
| 1050 | { |
| 1051 | switch (id.identifiers.board_name) |
| 1052 | { |
| 1053 | case 'VirtualBox': |
| 1054 | case 'Virtual Machine': |
| 1055 | ret = true; |
| 1056 | break; |
| 1057 | default: |
| 1058 | break; |
| 1059 | } |
| 1060 | } |
| 1061 | |
| 1062 | if (process.platform == 'win32' && !ret) |
| 1063 | { |
| 1064 | for(var i in id.identifiers.gpu_name) |
| 1065 | { |
| 1066 | if(id.identifiers.gpu_name[i].startsWith('VMware ')) |
| 1067 | { |
| 1068 | ret = true; |
| 1069 | break; |
| 1070 | } |
| 1071 | } |
| 1072 | } |
| 1073 | |
| 1074 | |
| 1075 | if (!ret) { ret = this.isDocker(); } |
| 1076 | return (ret); |
| 1077 | }; |
| 1078 | |
| 1079 | // bios_date = BIOS->ReleaseDate |
| 1080 | // bios_vendor = BIOS->Manufacturer |
| 1081 | // bios_version = BIOS->SMBIOSBIOSVersion |
| 1082 | // board_name = BASEBOARD->Product = ioreg/board-id |
| 1083 | // board_serial = BASEBOARD->SerialNumber = ioreg/serial-number | ioreg/IOPlatformSerialNumber |
| 1084 | // board_vendor = BASEBOARD->Manufacturer = ioreg/manufacturer |
| 1085 | // board_version = BASEBOARD->Version |