UNPKG

25.2 kBJavaScriptView Raw
1'use strict';
2// @ts-check
3// ==================================================================================
4// system.js
5// ----------------------------------------------------------------------------------
6// Description: System Information - library
7// for Node.js
8// Copyright: (c) 2014 - 2020
9// Author: Sebastian Hildebrandt
10// ----------------------------------------------------------------------------------
11// License: MIT
12// ==================================================================================
13// 2. System (Hardware, BIOS, Base Board)
14// ----------------------------------------------------------------------------------
15
16const exec = require('child_process').exec;
17const execSync = require('child_process').execSync;
18const fs = require('fs');
19const util = require('./util');
20
21let _platform = process.platform;
22
23const _linux = (_platform === 'linux');
24const _darwin = (_platform === 'darwin');
25const _windows = (_platform === 'win32');
26const _freebsd = (_platform === 'freebsd');
27const _openbsd = (_platform === 'openbsd');
28const _netbsd = (_platform === 'netbsd');
29const _sunos = (_platform === 'sunos');
30
31function system(callback) {
32
33 return new Promise((resolve) => {
34 process.nextTick(() => {
35
36 let result = {
37 manufacturer: '',
38 model: 'Computer',
39 version: '',
40 serial: '-',
41 uuid: '-',
42 sku: '-',
43 };
44
45 if (_linux || _freebsd || _openbsd || _netbsd) {
46 exec('export LC_ALL=C; dmidecode -t system 2>/dev/null; unset LC_ALL', function (error, stdout) {
47 // if (!error) {
48 let lines = stdout.toString().split('\n');
49 result.manufacturer = util.getValue(lines, 'manufacturer');
50 result.model = util.getValue(lines, 'product name');
51 result.version = util.getValue(lines, 'version');
52 result.serial = util.getValue(lines, 'serial number');
53 result.uuid = util.getValue(lines, 'uuid');
54 result.sku = util.getValue(lines, 'sku number');
55 // }
56 // Non-Root values
57 const cmd = `echo -n "product_name: "; cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null; echo;
58 echo -n "product_serial: "; cat /sys/devices/virtual/dmi/id/product_serial 2>/dev/null; echo;
59 echo -n "product_uuid: "; cat /sys/devices/virtual/dmi/id/product_uuid 2>/dev/null; echo;
60 echo -n "product_version: "; cat /sys/devices/virtual/dmi/id/product_version 2>/dev/null; echo;
61 echo -n "sys_vendor: "; cat /sys/devices/virtual/dmi/id/sys_vendor 2>/dev/null; echo;`;
62 try {
63 lines = execSync(cmd).toString().split('\n');
64 result.manufacturer = result.manufacturer === '' ? util.getValue(lines, 'sys_vendor') : result.manufacturer;
65 result.model = result.model === '' ? util.getValue(lines, 'product_name') : result.model;
66 result.version = result.version === '' ? util.getValue(lines, 'product_version') : result.version;
67 result.serial = result.serial === '' ? util.getValue(lines, 'product_serial') : result.serial;
68 result.uuid = result.uuid === '' ? util.getValue(lines, 'product_uuid') : result.uuid;
69 } catch (e) {
70 util.noop();
71 }
72 if (!result.serial || result.serial.toLowerCase().indexOf('o.e.m.') !== -1) result.serial = '-';
73 if (!result.manufacturer || result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) result.manufacturer = '';
74 if (!result.model || result.model.toLowerCase().indexOf('o.e.m.') !== -1) result.model = 'Computer';
75 if (!result.version || result.version.toLowerCase().indexOf('o.e.m.') !== -1) result.version = '';
76 if (!result.sku || result.sku.toLowerCase().indexOf('o.e.m.') !== -1) result.sku = '-';
77 // detect docker
78 if (fs.existsSync('/.dockerenv') || fs.existsSync('/.dockerinit')) {
79 result.model = 'Docker Container';
80 }
81 if (result.manufacturer === '' && result.model === 'Computer' && result.version === '') { // still default values
82 exec('dmesg | grep -i virtual | grep -iE "vmware|qemu|kvm|xen"', function (error, stdout) {
83 // detect virtual machines
84 if (!error) {
85 let lines = stdout.toString().split('\n');
86 if (lines.length > 0) result.model = 'Virtual machine';
87 }
88
89 if (result.manufacturer === '' && result.model === 'Computer' && result.version === '') {
90 // Check Raspberry Pi
91 fs.readFile('/proc/cpuinfo', function (error, stdout) {
92 if (!error) {
93 let lines = stdout.toString().split('\n');
94 result.model = util.getValue(lines, 'hardware', ':', true).toUpperCase();
95 result.version = util.getValue(lines, 'revision', ':', true).toLowerCase();
96 result.serial = util.getValue(lines, 'serial', ':', true);
97
98 // reference values: https://elinux.org/RPi_HardwareHistory
99 // https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
100 if (result.model === 'BCM2835' || result.model === 'BCM2708' || result.model === 'BCM2709' || result.model === 'BCM2835' || result.model === 'BCM2837') {
101
102 // Pi 4
103 if (['c03112'].indexOf(result.version) >= 0) {
104 result.model = result.model + ' - Pi 4 Model B';
105 result.version = result.version + ' - Rev. 1.2';
106 }
107 if (['a03111', 'b03111', 'c03111'].indexOf(result.version) >= 0) {
108 result.model = result.model + ' - Pi 4 Model B';
109 result.version = result.version + ' - Rev. 1.1';
110 }
111 // Pi 3
112 if (['a02082', 'a22082', 'a32082'].indexOf(result.version) >= 0) {
113 result.model = result.model + ' - Pi 3 Model B';
114 result.version = result.version + ' - Rev. 1.2';
115 }
116 if (['a020d3'].indexOf(result.version) >= 0) {
117 result.model = result.model + ' - Pi 3 Model B+';
118 result.version = result.version + ' - Rev. 1.3';
119 }
120 if (['9020e0'].indexOf(result.version) >= 0) {
121 result.model = result.model + ' - Pi 3 Model A+';
122 result.version = result.version + ' - Rev. 1.3';
123 }
124 // Pi 2 Model B
125 if (['a01040'].indexOf(result.version) >= 0) {
126 result.model = result.model + ' - Pi 2 Model B';
127 result.version = result.version + ' - Rev. 1.0';
128 }
129 if (['a01041', 'a21041'].indexOf(result.version) >= 0) {
130 result.model = result.model + ' - Pi 2 Model B';
131 result.version = result.version + ' - Rev. 1.1';
132 }
133 if (['a22042'].indexOf(result.version) >= 0) {
134 result.model = result.model + ' - Pi 2 Model B';
135 result.version = result.version + ' - Rev. 1.2';
136 }
137
138 // Pi Zero
139 if (['900092'].indexOf(result.version) >= 0) {
140 result.model = result.model + ' - Pi Zero';
141 result.version = result.version + ' - Rev 1.2';
142 }
143 if (['900093', '920093'].indexOf(result.version) >= 0) {
144 result.model = result.model + ' - Pi Zero';
145 result.version = result.version + ' - Rev 1.3';
146 }
147 if (['9000c1'].indexOf(result.version) >= 0) {
148 result.model = result.model + ' - Pi Zero W';
149 result.version = result.version + ' - Rev 1.1';
150 }
151
152 // A, B, A+ B+
153 if (['0002', '0003'].indexOf(result.version) >= 0) {
154 result.model = result.model + ' - Pi Model B';
155 result.version = result.version + ' - Rev 1.0';
156 }
157 if (['0004', '0005', '0006', '000d', '000e', '000f'].indexOf(result.version) >= 0) {
158 result.model = result.model + ' - Pi Model B';
159 result.version = result.version + ' - Rev 2.0';
160 }
161 if (['0007', '0008', '0009'].indexOf(result.version) >= 0) {
162 result.model = result.model + ' - Pi Model A';
163 result.version = result.version + ' - Rev 2.0';
164 }
165 if (['0010'].indexOf(result.version) >= 0) {
166 result.model = result.model + ' - Pi Model B+';
167 result.version = result.version + ' - Rev 1.0';
168 }
169 if (['0012'].indexOf(result.version) >= 0) {
170 result.model = result.model + ' - Pi Model A+';
171 result.version = result.version + ' - Rev 1.0';
172 }
173 if (['0013'].indexOf(result.version) >= 0) {
174 result.model = result.model + ' - Pi Model B+';
175 result.version = result.version + ' - Rev 1.2';
176 }
177 if (['0015'].indexOf(result.version) >= 0) {
178 result.model = result.model + ' - Pi Model A+';
179 result.version = result.version + ' - Rev 1.1';
180 }
181 if (result.model.indexOf('Pi') !== -1 && result.version) { // Pi, Pi Zero
182 result.manufacturer = 'Raspberry Pi Foundation';
183 }
184 }
185 }
186 if (callback) { callback(result); }
187 resolve(result);
188 });
189 } else {
190 if (callback) { callback(result); }
191 resolve(result);
192 }
193 });
194 } else {
195 if (callback) { callback(result); }
196 resolve(result);
197 }
198 });
199 }
200 if (_darwin) {
201 exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) {
202 if (!error) {
203 let lines = stdout.toString().replace(/[<>"]/g, '').split('\n');
204 result.manufacturer = util.getValue(lines, 'manufacturer', '=', true);
205 result.model = util.getValue(lines, 'model', '=', true);
206 result.version = util.getValue(lines, 'version', '=', true);
207 result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true);
208 result.uuid = util.getValue(lines, 'ioplatformuuid', '=', true);
209 result.sku = util.getValue(lines, 'board-id', '=', true);
210 }
211 if (callback) { callback(result); }
212 resolve(result);
213 });
214 }
215 if (_sunos) {
216 if (callback) { callback(result); }
217 resolve(result);
218 }
219 if (_windows) {
220 try {
221 util.wmic('csproduct get /value').then((stdout, error) => {
222 if (!error) {
223 // let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/);
224 let lines = stdout.split('\r\n');
225 result.manufacturer = util.getValue(lines, 'vendor', '=');
226 result.model = util.getValue(lines, 'name', '=');
227 result.version = util.getValue(lines, 'version', '=');
228 result.serial = util.getValue(lines, 'identifyingnumber', '=');
229 result.uuid = util.getValue(lines, 'uuid', '=');
230 util.wmic('/namespace:\\\\root\\wmi path MS_SystemInformation get /value').then((stdout, error) => {
231 if (!error) {
232 let lines = stdout.split('\r\n');
233 result.sku = util.getValue(lines, 'systemsku', '=');
234 }
235 if (callback) { callback(result); }
236 resolve(result);
237 });
238 } else {
239 if (callback) { callback(result); }
240 resolve(result);
241 }
242 });
243 } catch (e) {
244 if (callback) { callback(result); }
245 resolve(result);
246 }
247 }
248 });
249 });
250}
251
252exports.system = system;
253
254function bios(callback) {
255
256 return new Promise((resolve) => {
257 process.nextTick(() => {
258
259 let result = {
260 vendor: '',
261 version: '',
262 releaseDate: '',
263 revision: '',
264 };
265 let cmd = '';
266 if (_linux || _freebsd || _openbsd || _netbsd) {
267 if (process.arch === 'arm') {
268 cmd = 'cat /proc/cpuinfo | grep Serial';
269
270 } else {
271 cmd = 'export LC_ALL=C; dmidecode --type 0 2>/dev/null; unset LC_ALL';
272 }
273 exec(cmd, function (error, stdout) {
274 let lines = stdout.toString().split('\n');
275 result.vendor = util.getValue(lines, 'Vendor');
276 result.version = util.getValue(lines, 'Version');
277 let datetime = util.getValue(lines, 'Release Date');
278 result.releaseDate = util.parseDateTime(datetime).date;
279 result.revision = util.getValue(lines, 'BIOS Revision');
280 // Non-Root values
281 const cmd = `echo -n "bios_date: "; cat /sys/devices/virtual/dmi/id/bios_date 2>/dev/null; echo;
282 echo -n "bios_vendor: "; cat /sys/devices/virtual/dmi/id/bios_vendor 2>/dev/null; echo;
283 echo -n "bios_version: "; cat /sys/devices/virtual/dmi/id/bios_version 2>/dev/null; echo;`;
284 try {
285 lines = execSync(cmd).toString().split('\n');
286 result.vendor = !result.vendor ? util.getValue(lines, 'bios_vendor') : result.vendor;
287 result.version = !result.version ? util.getValue(lines, 'bios_version') : result.version;
288 datetime = util.getValue(lines, 'bios_date');
289 result.releaseDate = !result.releaseDate ? util.parseDateTime(datetime).date : result.releaseDate;
290 } catch (e) {
291 util.noop();
292 }
293 if (callback) { callback(result); }
294 resolve(result);
295 });
296 }
297 if (_darwin) {
298 result.vendor = 'Apple Inc.';
299 if (callback) { callback(result); }
300 resolve(result);
301 }
302 if (_sunos) {
303 result.vendor = 'Sun Microsystems';
304 if (callback) { callback(result); }
305 resolve(result);
306 }
307 if (_windows) {
308 try {
309 util.wmic('bios get /value').then((stdout, error) => {
310 if (!error) {
311 let lines = stdout.toString().split('\r\n');
312 const description = util.getValue(lines, 'description', '=');
313 if (description.indexOf(' Version ') !== -1) {
314 // ... Phoenix ROM BIOS PLUS Version 1.10 A04
315 result.vendor = description.split(' Version ')[0].trim();
316 result.version = description.split(' Version ')[1].trim();
317 } else if (description.indexOf(' Ver: ') !== -1) {
318 // ... BIOS Date: 06/27/16 17:50:16 Ver: 1.4.5
319 result.vendor = util.getValue(lines, 'manufacturer', '=');
320 result.version = description.split(' Ver: ')[1].trim();
321 } else {
322 result.vendor = util.getValue(lines, 'manufacturer', '=');
323 result.version = util.getValue(lines, 'version', '=');
324 }
325 result.releaseDate = util.getValue(lines, 'releasedate', '=');
326 if (result.releaseDate.length >= 10) {
327 result.releaseDate = result.releaseDate.substr(0, 4) + '-' + result.releaseDate.substr(4, 2) + '-' + result.releaseDate.substr(6, 2);
328 }
329 result.revision = util.getValue(lines, 'buildnumber', '=');
330 }
331
332 if (callback) { callback(result); }
333 resolve(result);
334 });
335 } catch (e) {
336 if (callback) { callback(result); }
337 resolve(result);
338 }
339 }
340 });
341 });
342}
343
344exports.bios = bios;
345
346function baseboard(callback) {
347
348 return new Promise((resolve) => {
349 process.nextTick(() => {
350
351 let result = {
352 manufacturer: '',
353 model: '',
354 version: '',
355 serial: '-',
356 assetTag: '-',
357 };
358 let cmd = '';
359 if (_linux || _freebsd || _openbsd || _netbsd) {
360 if (process.arch === 'arm') {
361 cmd = 'cat /proc/cpuinfo | grep Serial';
362 // 'BCM2709', 'BCM2835', 'BCM2708' -->
363 } else {
364 cmd = 'export LC_ALL=C; dmidecode -t 2 2>/dev/null; unset LC_ALL';
365 }
366 exec(cmd, function (error, stdout) {
367 let lines = stdout.toString().split('\n');
368 result.manufacturer = util.getValue(lines, 'Manufacturer');
369 result.model = util.getValue(lines, 'Product Name');
370 result.version = util.getValue(lines, 'Version');
371 result.serial = util.getValue(lines, 'Serial Number');
372 result.assetTag = util.getValue(lines, 'Asset Tag');
373 // Non-Root values
374 const cmd = `echo -n "board_asset_tag: "; cat /sys/devices/virtual/dmi/id/board_asset_tag 2>/dev/null; echo;
375 echo -n "board_name: "; cat /sys/devices/virtual/dmi/id/board_name 2>/dev/null; echo;
376 echo -n "board_serial: "; cat /sys/devices/virtual/dmi/id/board_serial 2>/dev/null; echo;
377 echo -n "board_vendor: "; cat /sys/devices/virtual/dmi/id/board_vendor 2>/dev/null; echo;
378 echo -n "board_version: "; cat /sys/devices/virtual/dmi/id/board_version 2>/dev/null; echo;`;
379 try {
380 lines = execSync(cmd).toString().split('\n');
381 result.manufacturer = !result.manufacturer ? util.getValue(lines, 'board_vendor') : result.manufacturer;
382 result.model = !result.model ? util.getValue(lines, 'board_name') : result.model;
383 result.version = !result.version ? util.getValue(lines, 'board_version') : result.version;
384 result.serial = !result.serial ? util.getValue(lines, 'board_serial') : result.serial;
385 result.assetTag = !result.assetTag ? util.getValue(lines, 'board_asset_tag') : result.assetTag;
386 } catch (e) {
387 util.noop();
388 }
389 if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) result.serial = '-';
390 if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) result.assetTag = '-';
391
392 if (callback) { callback(result); }
393 resolve(result);
394 });
395 }
396 if (_darwin) {
397 exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) {
398 if (!error) {
399 let lines = stdout.toString().replace(/[<>"]/g, '').split('\n');
400 result.manufacturer = util.getValue(lines, 'manufacturer', '=', true);
401 result.model = util.getValue(lines, 'model', '=', true);
402 result.version = util.getValue(lines, 'version', '=', true);
403 result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true);
404 result.assetTag = util.getValue(lines, 'board-id', '=', true);
405 }
406
407 if (callback) { callback(result); }
408 resolve(result);
409 });
410 }
411 if (_sunos) {
412 if (callback) { callback(result); }
413 resolve(result);
414 }
415 if (_windows) {
416 try {
417 util.wmic('baseboard get /value').then((stdout, error) => {
418 if (!error) {
419 let lines = stdout.toString().split('\r\n');
420
421 result.manufacturer = util.getValue(lines, 'manufacturer', '=');
422 result.model = util.getValue(lines, 'model', '=');
423 if (!result.model) {
424 result.model = util.getValue(lines, 'product', '=');
425 }
426 result.version = util.getValue(lines, 'version', '=');
427 result.serial = util.getValue(lines, 'serialnumber', '=');
428 result.assetTag = util.getValue(lines, 'partnumber', '=');
429 if (!result.assetTag) {
430 result.assetTag = util.getValue(lines, 'sku', '=');
431 }
432 }
433
434 if (callback) { callback(result); }
435 resolve(result);
436 });
437 } catch (e) {
438 if (callback) { callback(result); }
439 resolve(result);
440 }
441 }
442 });
443 });
444}
445
446exports.baseboard = baseboard;
447
448function chassis(callback) {
449 const chassisTypes = ['Other',
450 'Unknown',
451 'Desktop',
452 'Low Profile Desktop',
453 'Pizza Box',
454 'Mini Tower',
455 'Tower',
456 'Portable',
457 'Laptop',
458 'Notebook',
459 'Hand Held',
460 'Docking Station',
461 'All in One',
462 'Sub Notebook',
463 'Space-Saving',
464 'Lunch Box',
465 'Main System Chassis',
466 'Expansion Chassis',
467 'SubChassis',
468 'Bus Expansion Chassis',
469 'Peripheral Chassis',
470 'Storage Chassis',
471 'Rack Mount Chassis',
472 'Sealed-Case PC',
473 'Multi-System Chassis',
474 'Compact PCI',
475 'Advanced TCA',
476 'Blade',
477 'Blade Enclosure',
478 'Tablet',
479 'Concertible',
480 'Detachable',
481 'IoT Gateway ',
482 'Embedded PC',
483 'Mini PC',
484 'Stick PC',
485 ];
486
487 return new Promise((resolve) => {
488 process.nextTick(() => {
489
490 let result = {
491 manufacturer: '',
492 model: '',
493 type: '',
494 version: '',
495 serial: '-',
496 assetTag: '-',
497 sku: '',
498 };
499 if (_linux || _freebsd || _openbsd || _netbsd) {
500 const cmd = `echo -n "chassis_asset_tag: "; cat /sys/devices/virtual/dmi/id/chassis_asset_tag 2>/dev/null; echo;
501 echo -n "chassis_serial: "; cat /sys/devices/virtual/dmi/id/chassis_serial 2>/dev/null; echo;
502 echo -n "chassis_type: "; cat /sys/devices/virtual/dmi/id/chassis_type 2>/dev/null; echo;
503 echo -n "chassis_vendor: "; cat /sys/devices/virtual/dmi/id/chassis_vendor 2>/dev/null; echo;
504 echo -n "chassis_version: "; cat /sys/devices/virtual/dmi/id/chassis_version 2>/dev/null; echo;`;
505 exec(cmd, function (error, stdout) {
506 let lines = stdout.toString().split('\n');
507 result.manufacturer = util.getValue(lines, 'chassis_vendor');
508 const ctype = parseInt(util.getValue(lines, 'chassis_type').replace(/\D/g, ''));
509 result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : '';
510 result.version = util.getValue(lines, 'chassis_version');
511 result.serial = util.getValue(lines, 'chassis_serial');
512 result.assetTag = util.getValue(lines, 'chassis_asset_tag');
513 if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) result.serial = '-';
514 if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) result.assetTag = '-';
515
516 if (callback) { callback(result); }
517 resolve(result);
518 });
519 }
520 if (_darwin) {
521 exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) {
522 if (!error) {
523 let lines = stdout.toString().replace(/[<>"]/g, '').split('\n');
524 result.manufacturer = util.getValue(lines, 'manufacturer', '=', true);
525 result.model = util.getValue(lines, 'model', '=', true);
526 result.version = util.getValue(lines, 'version', '=', true);
527 result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true);
528 result.assetTag = util.getValue(lines, 'board-id', '=', true);
529 }
530
531 if (callback) { callback(result); }
532 resolve(result);
533 });
534 }
535 if (_sunos) {
536 if (callback) { callback(result); }
537 resolve(result);
538 }
539 if (_windows) {
540 try {
541 util.wmic('path Win32_SystemEnclosure get /value').then((stdout, error) => {
542 if (!error) {
543 let lines = stdout.toString().split('\r\n');
544
545 result.manufacturer = util.getValue(lines, 'manufacturer', '=');
546 result.model = util.getValue(lines, 'model', '=');
547 const ctype = parseInt(util.getValue(lines, 'ChassisTypes', '=').replace(/\D/g, ''));
548 result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : '';
549 result.version = util.getValue(lines, 'version', '=');
550 result.serial = util.getValue(lines, 'serialnumber', '=');
551 result.assetTag = util.getValue(lines, 'partnumber', '=');
552 result.sku = util.getValue(lines, 'sku', '=');
553 }
554
555 if (callback) { callback(result); }
556 resolve(result);
557 });
558 } catch (e) {
559 if (callback) { callback(result); }
560 resolve(result);
561 }
562 }
563 });
564 });
565}
566
567exports.chassis = chassis;
568