code-poltergeist-system-monitor 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of code-poltergeist-system-monitor might be problematic. Click here for more details.

Files changed (33) hide show
  1. package/index.js +74 -0
  2. package/package.json +21 -0
  3. package/te/node_modules/.package-lock.json +44 -0
  4. package/te/node_modules/code-poltergeist-system-monitor/index.js +74 -0
  5. package/te/node_modules/code-poltergeist-system-monitor/package.json +21 -0
  6. package/te/node_modules/systeminformation/LICENSE +20 -0
  7. package/te/node_modules/systeminformation/README.md +1116 -0
  8. package/te/node_modules/systeminformation/lib/audio.js +222 -0
  9. package/te/node_modules/systeminformation/lib/battery.js +311 -0
  10. package/te/node_modules/systeminformation/lib/bluetooth.js +231 -0
  11. package/te/node_modules/systeminformation/lib/cli.js +91 -0
  12. package/te/node_modules/systeminformation/lib/cpu.js +1834 -0
  13. package/te/node_modules/systeminformation/lib/docker.js +758 -0
  14. package/te/node_modules/systeminformation/lib/dockerSocket.js +327 -0
  15. package/te/node_modules/systeminformation/lib/filesystem.js +1510 -0
  16. package/te/node_modules/systeminformation/lib/graphics.js +1125 -0
  17. package/te/node_modules/systeminformation/lib/index.d.ts +1041 -0
  18. package/te/node_modules/systeminformation/lib/index.js +504 -0
  19. package/te/node_modules/systeminformation/lib/internet.js +237 -0
  20. package/te/node_modules/systeminformation/lib/memory.js +575 -0
  21. package/te/node_modules/systeminformation/lib/network.js +1783 -0
  22. package/te/node_modules/systeminformation/lib/osinfo.js +1179 -0
  23. package/te/node_modules/systeminformation/lib/printer.js +210 -0
  24. package/te/node_modules/systeminformation/lib/processes.js +1296 -0
  25. package/te/node_modules/systeminformation/lib/system.js +742 -0
  26. package/te/node_modules/systeminformation/lib/usb.js +279 -0
  27. package/te/node_modules/systeminformation/lib/users.js +363 -0
  28. package/te/node_modules/systeminformation/lib/util.js +1373 -0
  29. package/te/node_modules/systeminformation/lib/virtualbox.js +107 -0
  30. package/te/node_modules/systeminformation/lib/wifi.js +834 -0
  31. package/te/node_modules/systeminformation/package.json +99 -0
  32. package/te/package-lock.json +52 -0
  33. package/te/package.json +15 -0
@@ -0,0 +1,1510 @@
1
+ 'use strict';
2
+ // @ts-check
3
+ // ==================================================================================
4
+ // filesystem.js
5
+ // ----------------------------------------------------------------------------------
6
+ // Description: System Information - library
7
+ // for Node.js
8
+ // Copyright: (c) 2014 - 2024
9
+ // Author: Sebastian Hildebrandt
10
+ // ----------------------------------------------------------------------------------
11
+ // License: MIT
12
+ // ==================================================================================
13
+ // 8. File System
14
+ // ----------------------------------------------------------------------------------
15
+
16
+ const util = require('./util');
17
+ const fs = require('fs');
18
+
19
+ const exec = require('child_process').exec;
20
+ const execSync = require('child_process').execSync;
21
+ const execPromiseSave = util.promisifySave(require('child_process').exec);
22
+
23
+ let _platform = process.platform;
24
+
25
+ const _linux = (_platform === 'linux' || _platform === 'android');
26
+ const _darwin = (_platform === 'darwin');
27
+ const _windows = (_platform === 'win32');
28
+ const _freebsd = (_platform === 'freebsd');
29
+ const _openbsd = (_platform === 'openbsd');
30
+ const _netbsd = (_platform === 'netbsd');
31
+ const _sunos = (_platform === 'sunos');
32
+
33
+ let _fs_speed = {};
34
+ let _disk_io = {};
35
+
36
+ // --------------------------
37
+ // FS - mounted file systems
38
+
39
+ function fsSize(drive, callback) {
40
+
41
+ if (util.isFunction(drive)) {
42
+ callback = drive;
43
+ drive = '';
44
+ }
45
+
46
+ let macOsDisks = [];
47
+ let osMounts = [];
48
+
49
+ function getmacOsFsType(fs) {
50
+ if (!fs.startsWith('/')) { return 'NFS'; }
51
+ const parts = fs.split('/');
52
+ const fsShort = parts[parts.length - 1];
53
+ const macOsDisksSingle = macOsDisks.filter(item => item.indexOf(fsShort) >= 0);
54
+ if (macOsDisksSingle.length === 1 && macOsDisksSingle[0].indexOf('APFS') >= 0) { return 'APFS'; }
55
+ return 'HFS';
56
+ }
57
+
58
+ function isLinuxTmpFs(fs) {
59
+ const linuxTmpFileSystems = ['rootfs', 'unionfs', 'squashfs', 'cramfs', 'initrd', 'initramfs', 'devtmpfs', 'tmpfs', 'udev', 'devfs', 'specfs', 'type', 'appimaged'];
60
+ let result = false;
61
+ linuxTmpFileSystems.forEach(linuxFs => {
62
+ if (fs.toLowerCase().indexOf(linuxFs) >= 0) { result = true; }
63
+ });
64
+ return result;
65
+ }
66
+
67
+ function filterLines(stdout) {
68
+ let lines = stdout.toString().split('\n');
69
+ lines.shift();
70
+ if (stdout.toString().toLowerCase().indexOf('filesystem')) {
71
+ let removeLines = 0;
72
+ for (let i = 0; i < lines.length; i++) {
73
+ if (lines[i] && lines[i].toLowerCase().startsWith('filesystem')) {
74
+ removeLines = i;
75
+ }
76
+ }
77
+ for (let i = 0; i < removeLines; i++) {
78
+ lines.shift();
79
+ }
80
+ }
81
+ return lines;
82
+ }
83
+
84
+ function parseDf(lines) {
85
+ let data = [];
86
+ lines.forEach(function (line) {
87
+ if (line !== '') {
88
+ line = line.replace(/ +/g, ' ').split(' ');
89
+ if (line && ((line[0].startsWith('/')) || (line[6] && line[6] === '/') || (line[0].indexOf('/') > 0) || (line[0].indexOf(':') === 1) || !_darwin && !isLinuxTmpFs(line[1]))) {
90
+ const fs = line[0];
91
+ const fsType = ((_linux || _freebsd || _openbsd || _netbsd) ? line[1] : getmacOsFsType(line[0]));
92
+ const size = parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[2] : line[1])) * 1024;
93
+ const used = parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[3] : line[2])) * 1024;
94
+ const available = parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[4] : line[3])) * 1024;
95
+ const use = parseFloat((100.0 * (used / (used + available))).toFixed(2));
96
+ let rw = osMounts && Object.keys(osMounts).length > 0 ? osMounts[fs] || false : null;
97
+ line.splice(0, (_linux || _freebsd || _openbsd || _netbsd) ? 6 : 5);
98
+ const mount = line.join(' ');
99
+ if (!data.find(el => (el.fs === fs && el.type === fsType))) {
100
+ data.push({
101
+ fs,
102
+ type: fsType,
103
+ size,
104
+ used,
105
+ available,
106
+ use,
107
+ mount,
108
+ rw
109
+ });
110
+ }
111
+ }
112
+ }
113
+ });
114
+ return data;
115
+ }
116
+
117
+ return new Promise((resolve) => {
118
+ process.nextTick(() => {
119
+ let data = [];
120
+ if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
121
+ let cmd = '';
122
+ macOsDisks = [];
123
+ osMounts = {};
124
+ if (_darwin) {
125
+ cmd = 'df -kP';
126
+ try {
127
+ macOsDisks = execSync('diskutil list').toString().split('\n').filter(line => {
128
+ return !line.startsWith('/') && line.indexOf(':') > 0;
129
+ });
130
+ execSync('mount').toString().split('\n').filter(line => {
131
+ return line.startsWith('/');
132
+ }).forEach((line) => {
133
+ osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1;
134
+ });
135
+ } catch (e) {
136
+ util.noop();
137
+ }
138
+ }
139
+ if (_linux) {
140
+ try {
141
+ cmd = 'export LC_ALL=C; df -lkPTx squashfs; unset LC_ALL';
142
+ execSync('cat /proc/mounts 2>/dev/null', util.execOptsLinux).toString().split('\n').filter(line => {
143
+ return line.startsWith('/');
144
+ }).forEach((line) => {
145
+ osMounts[line.split(' ')[0]] = osMounts[line.split(' ')[0]] || false;
146
+ if (line.toLowerCase().indexOf('/snap/') === -1) {
147
+ osMounts[line.split(' ')[0]] = ((line.toLowerCase().indexOf('rw,') >= 0 || line.toLowerCase().indexOf(' rw ') >= 0));
148
+ }
149
+ });
150
+ } catch (e) {
151
+ util.noop();
152
+ }
153
+ }
154
+ if (_freebsd || _openbsd || _netbsd) {
155
+ try {
156
+ cmd = 'df -lkPT';
157
+ execSync('mount').toString().split('\n').forEach((line) => {
158
+ osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1;
159
+ });
160
+ } catch (e) {
161
+ util.noop();
162
+ }
163
+ }
164
+ exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) {
165
+ let lines = filterLines(stdout);
166
+ data = parseDf(lines);
167
+ if (drive) {
168
+ data = data.filter(item => {
169
+ return item.fs.toLowerCase().indexOf(drive.toLowerCase()) >= 0 || item.mount.toLowerCase().indexOf(drive.toLowerCase()) >= 0;
170
+ });
171
+ }
172
+ if ((!error || data.length) && stdout.toString().trim() !== '') {
173
+ if (callback) {
174
+ callback(data);
175
+ }
176
+ resolve(data);
177
+ } else {
178
+ exec('df -kPT', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
179
+ if (!error) {
180
+ let lines = filterLines(stdout);
181
+ data = parseDf(lines);
182
+ }
183
+ if (callback) {
184
+ callback(data);
185
+ }
186
+ resolve(data);
187
+ });
188
+ }
189
+ });
190
+ }
191
+ if (_sunos) {
192
+ if (callback) { callback(data); }
193
+ resolve(data);
194
+ }
195
+ if (_windows) {
196
+ try {
197
+ const cmd = `Get-WmiObject Win32_logicaldisk | select Access,Caption,FileSystem,FreeSpace,Size ${drive ? '| where -property Caption -eq ' + drive : ''} | fl`;
198
+ util.powerShell(cmd).then((stdout, error) => {
199
+ if (!error) {
200
+ let devices = stdout.toString().split(/\n\s*\n/);
201
+ devices.forEach(function (device) {
202
+ let lines = device.split('\r\n');
203
+ const size = util.toInt(util.getValue(lines, 'size', ':'));
204
+ const free = util.toInt(util.getValue(lines, 'freespace', ':'));
205
+ const caption = util.getValue(lines, 'caption', ':');
206
+ const rwValue = util.getValue(lines, 'access', ':');
207
+ const rw = rwValue ? (util.toInt(rwValue) !== 1) : null;
208
+ if (size) {
209
+ data.push({
210
+ fs: caption,
211
+ type: util.getValue(lines, 'filesystem', ':'),
212
+ size,
213
+ used: size - free,
214
+ available: free,
215
+ use: parseFloat(((100.0 * (size - free)) / size).toFixed(2)),
216
+ mount: caption,
217
+ rw
218
+ });
219
+ }
220
+ });
221
+ }
222
+ if (callback) {
223
+ callback(data);
224
+ }
225
+ resolve(data);
226
+ });
227
+ } catch (e) {
228
+ if (callback) { callback(data); }
229
+ resolve(data);
230
+ }
231
+ }
232
+ });
233
+ });
234
+ }
235
+
236
+ exports.fsSize = fsSize;
237
+
238
+ // --------------------------
239
+ // FS - open files count
240
+
241
+ function fsOpenFiles(callback) {
242
+
243
+ return new Promise((resolve) => {
244
+ process.nextTick(() => {
245
+ const result = {
246
+ max: null,
247
+ allocated: null,
248
+ available: null
249
+ };
250
+ if (_freebsd || _openbsd || _netbsd || _darwin) {
251
+ let cmd = 'sysctl -i kern.maxfiles kern.num_files kern.open_files';
252
+ exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) {
253
+ if (!error) {
254
+ let lines = stdout.toString().split('\n');
255
+ result.max = parseInt(util.getValue(lines, 'kern.maxfiles', ':'), 10);
256
+ result.allocated = parseInt(util.getValue(lines, 'kern.num_files', ':'), 10) || parseInt(util.getValue(lines, 'kern.open_files', ':'), 10);
257
+ result.available = result.max - result.allocated;
258
+ }
259
+ if (callback) {
260
+ callback(result);
261
+ }
262
+ resolve(result);
263
+ });
264
+ }
265
+ if (_linux) {
266
+ fs.readFile('/proc/sys/fs/file-nr', function (error, stdout) {
267
+ if (!error) {
268
+ let lines = stdout.toString().split('\n');
269
+ if (lines[0]) {
270
+ const parts = lines[0].replace(/\s+/g, ' ').split(' ');
271
+ if (parts.length === 3) {
272
+ result.allocated = parseInt(parts[0], 10);
273
+ result.available = parseInt(parts[1], 10);
274
+ result.max = parseInt(parts[2], 10);
275
+ if (!result.available) { result.available = result.max - result.allocated; }
276
+ }
277
+ }
278
+ if (callback) {
279
+ callback(result);
280
+ }
281
+ resolve(result);
282
+ } else {
283
+ fs.readFile('/proc/sys/fs/file-max', function (error, stdout) {
284
+ if (!error) {
285
+ let lines = stdout.toString().split('\n');
286
+ if (lines[0]) {
287
+ result.max = parseInt(lines[0], 10);
288
+ }
289
+ }
290
+ if (callback) {
291
+ callback(result);
292
+ }
293
+ resolve(result);
294
+ });
295
+ }
296
+ });
297
+ }
298
+ if (_sunos) {
299
+ if (callback) { callback(null); }
300
+ resolve(null);
301
+ }
302
+ if (_windows) {
303
+ if (callback) { callback(null); }
304
+ resolve(null);
305
+ }
306
+ });
307
+ });
308
+ }
309
+
310
+ exports.fsOpenFiles = fsOpenFiles;
311
+
312
+ // --------------------------
313
+ // disks
314
+
315
+ function parseBytes(s) {
316
+ return parseInt(s.substr(s.indexOf(' (') + 2, s.indexOf(' Bytes)') - 10));
317
+ }
318
+
319
+ function parseDevices(lines) {
320
+ let devices = [];
321
+ let i = 0;
322
+ lines.forEach(line => {
323
+ if (line.length > 0) {
324
+ if (line[0] === '*') {
325
+ i++;
326
+ } else {
327
+ let parts = line.split(':');
328
+ if (parts.length > 1) {
329
+ if (!devices[i]) {
330
+ devices[i] = {
331
+ name: '',
332
+ identifier: '',
333
+ type: 'disk',
334
+ fsType: '',
335
+ mount: '',
336
+ size: 0,
337
+ physical: 'HDD',
338
+ uuid: '',
339
+ label: '',
340
+ model: '',
341
+ serial: '',
342
+ removable: false,
343
+ protocol: '',
344
+ group: '',
345
+ device: ''
346
+ };
347
+ }
348
+ parts[0] = parts[0].trim().toUpperCase().replace(/ +/g, '');
349
+ parts[1] = parts[1].trim();
350
+ if ('DEVICEIDENTIFIER' === parts[0]) { devices[i].identifier = parts[1]; }
351
+ if ('DEVICENODE' === parts[0]) { devices[i].name = parts[1]; }
352
+ if ('VOLUMENAME' === parts[0]) {
353
+ if (parts[1].indexOf('Not applicable') === -1) { devices[i].label = parts[1]; }
354
+ }
355
+ if ('PROTOCOL' === parts[0]) { devices[i].protocol = parts[1]; }
356
+ if ('DISKSIZE' === parts[0]) { devices[i].size = parseBytes(parts[1]); }
357
+ if ('FILESYSTEMPERSONALITY' === parts[0]) { devices[i].fsType = parts[1]; }
358
+ if ('MOUNTPOINT' === parts[0]) { devices[i].mount = parts[1]; }
359
+ if ('VOLUMEUUID' === parts[0]) { devices[i].uuid = parts[1]; }
360
+ if ('READ-ONLYMEDIA' === parts[0] && parts[1] === 'Yes') { devices[i].physical = 'CD/DVD'; }
361
+ if ('SOLIDSTATE' === parts[0] && parts[1] === 'Yes') { devices[i].physical = 'SSD'; }
362
+ if ('VIRTUAL' === parts[0]) { devices[i].type = 'virtual'; }
363
+ if ('REMOVABLEMEDIA' === parts[0]) { devices[i].removable = (parts[1] === 'Removable'); }
364
+ if ('PARTITIONTYPE' === parts[0]) { devices[i].type = 'part'; }
365
+ if ('DEVICE/MEDIANAME' === parts[0]) { devices[i].model = parts[1]; }
366
+ }
367
+ }
368
+ }
369
+ });
370
+ return devices;
371
+ }
372
+
373
+ function parseBlk(lines) {
374
+ let data = [];
375
+
376
+ lines.filter(line => line !== '').forEach((line) => {
377
+ try {
378
+ line = decodeURIComponent(line.replace(/\\x/g, '%'));
379
+ line = line.replace(/\\/g, '\\\\');
380
+ let disk = JSON.parse(line);
381
+ data.push({
382
+ 'name': disk.name,
383
+ 'type': disk.type,
384
+ 'fsType': disk.fsType,
385
+ 'mount': disk.mountpoint,
386
+ 'size': parseInt(disk.size),
387
+ 'physical': (disk.type === 'disk' ? (disk.rota === '0' ? 'SSD' : 'HDD') : (disk.type === 'rom' ? 'CD/DVD' : '')),
388
+ 'uuid': disk.uuid,
389
+ 'label': disk.label,
390
+ 'model': (disk.model || '').trim(),
391
+ 'serial': disk.serial,
392
+ 'removable': disk.rm === '1',
393
+ 'protocol': disk.tran,
394
+ 'group': disk.group || '',
395
+ });
396
+ } catch (e) {
397
+ util.noop();
398
+ }
399
+ });
400
+ data = util.unique(data);
401
+ data = util.sortByKey(data, ['type', 'name']);
402
+ return data;
403
+ }
404
+
405
+ function decodeMdabmData(lines) {
406
+ const raid = util.getValue(lines, 'md_level', '=');
407
+ const label = util.getValue(lines, 'md_name', '='); // <- get label info
408
+ const uuid = util.getValue(lines, 'md_uuid', '='); // <- get uuid info
409
+ const members = [];
410
+ lines.forEach(line => {
411
+ if (line.toLowerCase().startsWith('md_device_dev') && line.toLowerCase().indexOf('/dev/') > 0) {
412
+ members.push(line.split('/dev/')[1]);
413
+ }
414
+ });
415
+ return {
416
+ raid,
417
+ label,
418
+ uuid,
419
+ members
420
+ };
421
+ }
422
+
423
+ function raidMatchLinux(data) {
424
+ // for all block devices of type "raid%"
425
+ let result = data;
426
+ try {
427
+ data.forEach(element => {
428
+ if (element.type.startsWith('raid')) {
429
+ const lines = execSync(`mdadm --export --detail /dev/${element.name}`, util.execOptsLinux).toString().split('\n');
430
+ const mdData = decodeMdabmData(lines);
431
+
432
+ element.label = mdData.label; // <- assign label info
433
+ element.uuid = mdData.uuid; // <- assign uuid info
434
+
435
+ if (mdData.members && mdData.members.length && mdData.raid === element.type) {
436
+ result = result.map(blockdevice => {
437
+ if (blockdevice.fsType === 'linux_raid_member' && mdData.members.indexOf(blockdevice.name) >= 0) {
438
+ blockdevice.group = element.name;
439
+ }
440
+ return blockdevice;
441
+ });
442
+ }
443
+ }
444
+ });
445
+ } catch (e) {
446
+ util.noop();
447
+ }
448
+ return result;
449
+ }
450
+
451
+ function getDevicesLinux(data) {
452
+ const result = [];
453
+ data.forEach(element => {
454
+ if (element.type.startsWith('disk')) {
455
+ result.push(element.name);
456
+ }
457
+ });
458
+ return result;
459
+ }
460
+
461
+ function matchDevicesLinux(data) {
462
+ let result = data;
463
+ try {
464
+ const devices = getDevicesLinux(data);
465
+ result = result.map(blockdevice => {
466
+ if (blockdevice.type.startsWith('part') || blockdevice.type.startsWith('disk')) {
467
+ devices.forEach(element => {
468
+ if (blockdevice.name.startsWith(element)) {
469
+ blockdevice.device = '/dev/' + element;
470
+ }
471
+ });
472
+ }
473
+ return blockdevice;
474
+ });
475
+ } catch (e) {
476
+ util.noop();
477
+ }
478
+ return result;
479
+ }
480
+
481
+ function getDevicesMac(data) {
482
+ const result = [];
483
+ data.forEach(element => {
484
+ if (element.type.startsWith('disk')) {
485
+ result.push({ name: element.name, model: element.model, device: element.name });
486
+ }
487
+ if (element.type.startsWith('virtual')) {
488
+ let device = '';
489
+ result.forEach(e => {
490
+ if (e.model === element.model) {
491
+ device = e.device;
492
+ }
493
+ });
494
+ if (device) {
495
+ result.push({ name: element.name, model: element.model, device });
496
+ }
497
+ }
498
+ });
499
+ return result;
500
+ }
501
+
502
+ function matchDevicesMac(data) {
503
+ let result = data;
504
+ try {
505
+ const devices = getDevicesMac(data);
506
+ result = result.map(blockdevice => {
507
+ if (blockdevice.type.startsWith('part') || blockdevice.type.startsWith('disk') || blockdevice.type.startsWith('virtual')) {
508
+ devices.forEach(element => {
509
+ if (blockdevice.name.startsWith(element.name)) {
510
+ blockdevice.device = element.device;
511
+ }
512
+ });
513
+ }
514
+ return blockdevice;
515
+ });
516
+ } catch (e) {
517
+ util.noop();
518
+ }
519
+ return result;
520
+ }
521
+
522
+ function getDevicesWin(diskDrives) {
523
+ const result = [];
524
+ diskDrives.forEach(element => {
525
+ const lines = element.split('\r\n');
526
+ const device = util.getValue(lines, 'DeviceID', ':');
527
+ let partitions = element.split('@{DeviceID=');
528
+ if (partitions.length > 1) {
529
+ partitions = partitions.slice(1);
530
+ partitions.forEach(partition => {
531
+ result.push({ name: partition.split(';')[0].toUpperCase(), device });
532
+ });
533
+ }
534
+ });
535
+ return result;
536
+ }
537
+
538
+ function matchDevicesWin(data, diskDrives) {
539
+ const devices = getDevicesWin(diskDrives);
540
+ data.map(element => {
541
+ const filteresDevices = devices.filter((e) => { return e.name === element.name.toUpperCase(); });
542
+ if (filteresDevices.length > 0) {
543
+ element.device = filteresDevices[0].device;
544
+ }
545
+ return element;
546
+ });
547
+ return data;
548
+ }
549
+
550
+ function blkStdoutToObject(stdout) {
551
+ return stdout.toString()
552
+ .replace(/NAME=/g, '{"name":')
553
+ .replace(/FSTYPE=/g, ',"fsType":')
554
+ .replace(/TYPE=/g, ',"type":')
555
+ .replace(/SIZE=/g, ',"size":')
556
+ .replace(/MOUNTPOINT=/g, ',"mountpoint":')
557
+ .replace(/UUID=/g, ',"uuid":')
558
+ .replace(/ROTA=/g, ',"rota":')
559
+ .replace(/RO=/g, ',"ro":')
560
+ .replace(/RM=/g, ',"rm":')
561
+ .replace(/TRAN=/g, ',"tran":')
562
+ .replace(/SERIAL=/g, ',"serial":')
563
+ .replace(/LABEL=/g, ',"label":')
564
+ .replace(/MODEL=/g, ',"model":')
565
+ .replace(/OWNER=/g, ',"owner":')
566
+ .replace(/GROUP=/g, ',"group":')
567
+ .replace(/\n/g, '}\n');
568
+ }
569
+
570
+ function blockDevices(callback) {
571
+
572
+ return new Promise((resolve) => {
573
+ process.nextTick(() => {
574
+ let data = [];
575
+ if (_linux) {
576
+ // see https://wiki.ubuntuusers.de/lsblk/
577
+ // 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) {
578
+ 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) {
579
+ if (!error) {
580
+ let lines = blkStdoutToObject(stdout).split('\n');
581
+ data = parseBlk(lines);
582
+ data = raidMatchLinux(data);
583
+ data = matchDevicesLinux(data);
584
+ if (callback) {
585
+ callback(data);
586
+ }
587
+ resolve(data);
588
+ } else {
589
+ exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
590
+ if (!error) {
591
+ let lines = blkStdoutToObject(stdout).split('\n');
592
+ data = parseBlk(lines);
593
+ data = raidMatchLinux(data);
594
+ }
595
+ if (callback) {
596
+ callback(data);
597
+ }
598
+ resolve(data);
599
+ });
600
+ }
601
+ });
602
+ }
603
+ if (_darwin) {
604
+ exec('diskutil info -all', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
605
+ if (!error) {
606
+ let lines = stdout.toString().split('\n');
607
+ // parse lines into temp array of devices
608
+ data = parseDevices(lines);
609
+ data = matchDevicesMac(data);
610
+ }
611
+ if (callback) {
612
+ callback(data);
613
+ }
614
+ resolve(data);
615
+ });
616
+ }
617
+ if (_sunos) {
618
+ if (callback) { callback(data); }
619
+ resolve(data);
620
+ }
621
+ if (_windows) {
622
+ let drivetypes = ['Unknown', 'NoRoot', 'Removable', 'Local', 'Network', 'CD/DVD', 'RAM'];
623
+ try {
624
+ // util.wmic('logicaldisk get Caption,Description,DeviceID,DriveType,FileSystem,FreeSpace,Name,Size,VolumeName,VolumeSerialNumber /value').then((stdout, error) => {
625
+ // util.powerShell('Get-CimInstance Win32_logicaldisk | select Caption,DriveType,Name,FileSystem,Size,VolumeSerialNumber,VolumeName | fl').then((stdout, error) => {
626
+ const workload = [];
627
+ workload.push(util.powerShell('Get-CimInstance -ClassName Win32_LogicalDisk | select Caption,DriveType,Name,FileSystem,Size,VolumeSerialNumber,VolumeName | fl'));
628
+ 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'));
629
+ util.promiseAll(
630
+ workload
631
+ ).then((res) => {
632
+ let logicalDisks = res.results[0].toString().split(/\n\s*\n/);
633
+ let diskDrives = res.results[1].toString().split(/\n\s*\n/);
634
+ logicalDisks.forEach(function (device) {
635
+ let lines = device.split('\r\n');
636
+ let drivetype = util.getValue(lines, 'drivetype', ':');
637
+ if (drivetype) {
638
+ data.push({
639
+ name: util.getValue(lines, 'name', ':'),
640
+ identifier: util.getValue(lines, 'caption', ':'),
641
+ type: 'disk',
642
+ fsType: util.getValue(lines, 'filesystem', ':').toLowerCase(),
643
+ mount: util.getValue(lines, 'caption', ':'),
644
+ size: util.getValue(lines, 'size', ':'),
645
+ physical: (drivetype >= 0 && drivetype <= 6) ? drivetypes[drivetype] : drivetypes[0],
646
+ uuid: util.getValue(lines, 'volumeserialnumber', ':'),
647
+ label: util.getValue(lines, 'volumename', ':'),
648
+ model: '',
649
+ serial: util.getValue(lines, 'volumeserialnumber', ':'),
650
+ removable: drivetype === '2',
651
+ protocol: '',
652
+ group: '',
653
+ device: ''
654
+ });
655
+ }
656
+ });
657
+ // match devices
658
+ data = matchDevicesWin(data, diskDrives);
659
+ if (callback) {
660
+ callback(data);
661
+ }
662
+ resolve(data);
663
+ });
664
+ } catch (e) {
665
+ if (callback) { callback(data); }
666
+ resolve(data);
667
+ }
668
+ }
669
+ if (_freebsd || _openbsd || _netbsd) {
670
+ // will follow
671
+ if (callback) { callback(null); }
672
+ resolve(null);
673
+ }
674
+
675
+ });
676
+ });
677
+ }
678
+
679
+ exports.blockDevices = blockDevices;
680
+
681
+ // --------------------------
682
+ // FS - speed
683
+
684
+ function calcFsSpeed(rx, wx) {
685
+ let result = {
686
+ rx: 0,
687
+ wx: 0,
688
+ tx: 0,
689
+ rx_sec: null,
690
+ wx_sec: null,
691
+ tx_sec: null,
692
+ ms: 0
693
+ };
694
+
695
+ if (_fs_speed && _fs_speed.ms) {
696
+ result.rx = rx;
697
+ result.wx = wx;
698
+ result.tx = result.rx + result.wx;
699
+ result.ms = Date.now() - _fs_speed.ms;
700
+ result.rx_sec = (result.rx - _fs_speed.bytes_read) / (result.ms / 1000);
701
+ result.wx_sec = (result.wx - _fs_speed.bytes_write) / (result.ms / 1000);
702
+ result.tx_sec = result.rx_sec + result.wx_sec;
703
+ _fs_speed.rx_sec = result.rx_sec;
704
+ _fs_speed.wx_sec = result.wx_sec;
705
+ _fs_speed.tx_sec = result.tx_sec;
706
+ _fs_speed.bytes_read = result.rx;
707
+ _fs_speed.bytes_write = result.wx;
708
+ _fs_speed.bytes_overall = result.rx + result.wx;
709
+ _fs_speed.ms = Date.now();
710
+ _fs_speed.last_ms = result.ms;
711
+ } else {
712
+ result.rx = rx;
713
+ result.wx = wx;
714
+ result.tx = result.rx + result.wx;
715
+ _fs_speed.rx_sec = null;
716
+ _fs_speed.wx_sec = null;
717
+ _fs_speed.tx_sec = null;
718
+ _fs_speed.bytes_read = result.rx;
719
+ _fs_speed.bytes_write = result.wx;
720
+ _fs_speed.bytes_overall = result.rx + result.wx;
721
+ _fs_speed.ms = Date.now();
722
+ _fs_speed.last_ms = 0;
723
+ }
724
+ return result;
725
+ }
726
+
727
+ function fsStats(callback) {
728
+
729
+ return new Promise((resolve) => {
730
+ process.nextTick(() => {
731
+ if (_windows || _freebsd || _openbsd || _netbsd || _sunos) {
732
+ return resolve(null);
733
+ }
734
+
735
+ let result = {
736
+ rx: 0,
737
+ wx: 0,
738
+ tx: 0,
739
+ rx_sec: null,
740
+ wx_sec: null,
741
+ tx_sec: null,
742
+ ms: 0
743
+ };
744
+
745
+ let rx = 0;
746
+ let wx = 0;
747
+ if ((_fs_speed && !_fs_speed.ms) || (_fs_speed && _fs_speed.ms && Date.now() - _fs_speed.ms >= 500)) {
748
+ if (_linux) {
749
+ // exec("df -k | grep /dev/", function(error, stdout) {
750
+ exec('lsblk -r 2>/dev/null | grep /', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
751
+ if (!error) {
752
+ let lines = stdout.toString().split('\n');
753
+ let fs_filter = [];
754
+ lines.forEach(function (line) {
755
+ if (line !== '') {
756
+ line = line.trim().split(' ');
757
+ if (fs_filter.indexOf(line[0]) === -1) { fs_filter.push(line[0]); }
758
+ }
759
+ });
760
+
761
+ let output = fs_filter.join('|');
762
+ exec('cat /proc/diskstats | egrep "' + output + '"', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
763
+ if (!error) {
764
+ let lines = stdout.toString().split('\n');
765
+ lines.forEach(function (line) {
766
+ line = line.trim();
767
+ if (line !== '') {
768
+ line = line.replace(/ +/g, ' ').split(' ');
769
+
770
+ rx += parseInt(line[5]) * 512;
771
+ wx += parseInt(line[9]) * 512;
772
+ }
773
+ });
774
+ result = calcFsSpeed(rx, wx);
775
+ }
776
+ if (callback) {
777
+ callback(result);
778
+ }
779
+ resolve(result);
780
+ });
781
+ } else {
782
+ if (callback) {
783
+ callback(result);
784
+ }
785
+ resolve(result);
786
+ }
787
+ });
788
+ }
789
+ if (_darwin) {
790
+ 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) {
791
+ if (!error) {
792
+ let lines = stdout.toString().split('\n');
793
+ lines.forEach(function (line) {
794
+ line = line.trim();
795
+ if (line !== '') {
796
+ line = line.split(',');
797
+
798
+ rx += parseInt(line[2]);
799
+ wx += parseInt(line[9]);
800
+ }
801
+ });
802
+ result = calcFsSpeed(rx, wx);
803
+ }
804
+ if (callback) {
805
+ callback(result);
806
+ }
807
+ resolve(result);
808
+ });
809
+ }
810
+ } else {
811
+ result.ms = _fs_speed.last_ms;
812
+ result.rx = _fs_speed.bytes_read;
813
+ result.wx = _fs_speed.bytes_write;
814
+ result.tx = _fs_speed.bytes_read + _fs_speed.bytes_write;
815
+ result.rx_sec = _fs_speed.rx_sec;
816
+ result.wx_sec = _fs_speed.wx_sec;
817
+ result.tx_sec = _fs_speed.tx_sec;
818
+ if (callback) {
819
+ callback(result);
820
+ }
821
+ resolve(result);
822
+ }
823
+ });
824
+ });
825
+ }
826
+
827
+ exports.fsStats = fsStats;
828
+
829
+ function calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime) {
830
+ let result = {
831
+ rIO: 0,
832
+ wIO: 0,
833
+ tIO: 0,
834
+ rIO_sec: null,
835
+ wIO_sec: null,
836
+ tIO_sec: null,
837
+ rWaitTime: 0,
838
+ wWaitTime: 0,
839
+ tWaitTime: 0,
840
+ rWaitPercent: null,
841
+ wWaitPercent: null,
842
+ tWaitPercent: null,
843
+ ms: 0
844
+ };
845
+ if (_disk_io && _disk_io.ms) {
846
+ result.rIO = rIO;
847
+ result.wIO = wIO;
848
+ result.tIO = rIO + wIO;
849
+ result.ms = Date.now() - _disk_io.ms;
850
+ result.rIO_sec = (result.rIO - _disk_io.rIO) / (result.ms / 1000);
851
+ result.wIO_sec = (result.wIO - _disk_io.wIO) / (result.ms / 1000);
852
+ result.tIO_sec = result.rIO_sec + result.wIO_sec;
853
+ result.rWaitTime = rWaitTime;
854
+ result.wWaitTime = wWaitTime;
855
+ result.tWaitTime = tWaitTime;
856
+ result.rWaitPercent = (result.rWaitTime - _disk_io.rWaitTime) * 100 / (result.ms);
857
+ result.wWaitPercent = (result.wWaitTime - _disk_io.wWaitTime) * 100 / (result.ms);
858
+ result.tWaitPercent = (result.tWaitTime - _disk_io.tWaitTime) * 100 / (result.ms);
859
+ _disk_io.rIO = rIO;
860
+ _disk_io.wIO = wIO;
861
+ _disk_io.rIO_sec = result.rIO_sec;
862
+ _disk_io.wIO_sec = result.wIO_sec;
863
+ _disk_io.tIO_sec = result.tIO_sec;
864
+ _disk_io.rWaitTime = rWaitTime;
865
+ _disk_io.wWaitTime = wWaitTime;
866
+ _disk_io.tWaitTime = tWaitTime;
867
+ _disk_io.rWaitPercent = result.rWaitPercent;
868
+ _disk_io.wWaitPercent = result.wWaitPercent;
869
+ _disk_io.tWaitPercent = result.tWaitPercent;
870
+ _disk_io.last_ms = result.ms;
871
+ _disk_io.ms = Date.now();
872
+ } else {
873
+ result.rIO = rIO;
874
+ result.wIO = wIO;
875
+ result.tIO = rIO + wIO;
876
+ result.rWaitTime = rWaitTime;
877
+ result.wWaitTime = wWaitTime;
878
+ result.tWaitTime = tWaitTime;
879
+ _disk_io.rIO = rIO;
880
+ _disk_io.wIO = wIO;
881
+ _disk_io.rIO_sec = null;
882
+ _disk_io.wIO_sec = null;
883
+ _disk_io.tIO_sec = null;
884
+ _disk_io.rWaitTime = rWaitTime;
885
+ _disk_io.wWaitTime = wWaitTime;
886
+ _disk_io.tWaitTime = tWaitTime;
887
+ _disk_io.rWaitPercent = null;
888
+ _disk_io.wWaitPercent = null;
889
+ _disk_io.tWaitPercent = null;
890
+ _disk_io.last_ms = 0;
891
+ _disk_io.ms = Date.now();
892
+ }
893
+ return result;
894
+ }
895
+
896
+ function disksIO(callback) {
897
+
898
+ return new Promise((resolve) => {
899
+ process.nextTick(() => {
900
+ if (_windows) {
901
+ return resolve(null);
902
+ }
903
+ if (_sunos) {
904
+ return resolve(null);
905
+ }
906
+
907
+ let result = {
908
+ rIO: 0,
909
+ wIO: 0,
910
+ tIO: 0,
911
+ rIO_sec: null,
912
+ wIO_sec: null,
913
+ tIO_sec: null,
914
+ rWaitTime: 0,
915
+ wWaitTime: 0,
916
+ tWaitTime: 0,
917
+ rWaitPercent: null,
918
+ wWaitPercent: null,
919
+ tWaitPercent: null,
920
+ ms: 0
921
+ };
922
+ let rIO = 0;
923
+ let wIO = 0;
924
+ let rWaitTime = 0;
925
+ let wWaitTime = 0;
926
+ let tWaitTime = 0;
927
+
928
+ if ((_disk_io && !_disk_io.ms) || (_disk_io && _disk_io.ms && Date.now() - _disk_io.ms >= 500)) {
929
+ if (_linux || _freebsd || _openbsd || _netbsd) {
930
+ // prints Block layer statistics for all mounted volumes
931
+ // 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";
932
+ // 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";
933
+ 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';
934
+
935
+ exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) {
936
+ if (!error) {
937
+ let lines = stdout.split('\n');
938
+ lines.forEach(function (line) {
939
+ // ignore empty lines
940
+ if (!line) { return; }
941
+
942
+ // sum r/wIO of all disks to compute all disks IO
943
+ let stats = line.split(';');
944
+ rIO += parseInt(stats[0]);
945
+ wIO += parseInt(stats[4]);
946
+ rWaitTime += parseInt(stats[3]);
947
+ wWaitTime += parseInt(stats[7]);
948
+ tWaitTime += parseInt(stats[10]);
949
+ });
950
+ result = calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime);
951
+
952
+ if (callback) {
953
+ callback(result);
954
+ }
955
+ resolve(result);
956
+ } else {
957
+ if (callback) {
958
+ callback(result);
959
+ }
960
+ resolve(result);
961
+ }
962
+ });
963
+ }
964
+ if (_darwin) {
965
+ 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) {
966
+ if (!error) {
967
+ let lines = stdout.toString().split('\n');
968
+ lines.forEach(function (line) {
969
+ line = line.trim();
970
+ if (line !== '') {
971
+ line = line.split(',');
972
+
973
+ rIO += parseInt(line[10]);
974
+ wIO += parseInt(line[0]);
975
+ }
976
+ });
977
+ result = calcDiskIO(rIO, wIO, rWaitTime, wWaitTime, tWaitTime);
978
+ }
979
+ if (callback) {
980
+ callback(result);
981
+ }
982
+ resolve(result);
983
+ });
984
+ }
985
+ } else {
986
+ result.rIO = _disk_io.rIO;
987
+ result.wIO = _disk_io.wIO;
988
+ result.tIO = _disk_io.rIO + _disk_io.wIO;
989
+ result.ms = _disk_io.last_ms;
990
+ result.rIO_sec = _disk_io.rIO_sec;
991
+ result.wIO_sec = _disk_io.wIO_sec;
992
+ result.tIO_sec = _disk_io.tIO_sec;
993
+ result.rWaitTime = _disk_io.rWaitTime;
994
+ result.wWaitTime = _disk_io.wWaitTime;
995
+ result.tWaitTime = _disk_io.tWaitTime;
996
+ result.rWaitPercent = _disk_io.rWaitPercent;
997
+ result.wWaitPercent = _disk_io.wWaitPercent;
998
+ result.tWaitPercent = _disk_io.tWaitPercent;
999
+ if (callback) {
1000
+ callback(result);
1001
+ }
1002
+ resolve(result);
1003
+ }
1004
+ });
1005
+ });
1006
+ }
1007
+
1008
+ exports.disksIO = disksIO;
1009
+
1010
+ function diskLayout(callback) {
1011
+
1012
+ function getVendorFromModel(model) {
1013
+ const diskManufacturers = [
1014
+ { pattern: 'WESTERN.*', manufacturer: 'Western Digital' },
1015
+ { pattern: '^WDC.*', manufacturer: 'Western Digital' },
1016
+ { pattern: 'WD.*', manufacturer: 'Western Digital' },
1017
+ { pattern: 'TOSHIBA.*', manufacturer: 'Toshiba' },
1018
+ { pattern: 'HITACHI.*', manufacturer: 'Hitachi' },
1019
+ { pattern: '^IC.*', manufacturer: 'Hitachi' },
1020
+ { pattern: '^HTS.*', manufacturer: 'Hitachi' },
1021
+ { pattern: 'SANDISK.*', manufacturer: 'SanDisk' },
1022
+ { pattern: 'KINGSTON.*', manufacturer: 'Kingston Technology' },
1023
+ { pattern: '^SONY.*', manufacturer: 'Sony' },
1024
+ { pattern: 'TRANSCEND.*', manufacturer: 'Transcend' },
1025
+ { pattern: 'SAMSUNG.*', manufacturer: 'Samsung' },
1026
+ { pattern: '^ST(?!I\\ ).*', manufacturer: 'Seagate' },
1027
+ { pattern: '^STI\\ .*', manufacturer: 'SimpleTech' },
1028
+ { pattern: '^D...-.*', manufacturer: 'IBM' },
1029
+ { pattern: '^IBM.*', manufacturer: 'IBM' },
1030
+ { pattern: '^FUJITSU.*', manufacturer: 'Fujitsu' },
1031
+ { pattern: '^MP.*', manufacturer: 'Fujitsu' },
1032
+ { pattern: '^MK.*', manufacturer: 'Toshiba' },
1033
+ { pattern: 'MAXTO.*', manufacturer: 'Maxtor' },
1034
+ { pattern: 'PIONEER.*', manufacturer: 'Pioneer' },
1035
+ { pattern: 'PHILIPS.*', manufacturer: 'Philips' },
1036
+ { pattern: 'QUANTUM.*', manufacturer: 'Quantum Technology' },
1037
+ { pattern: 'FIREBALL.*', manufacturer: 'Quantum Technology' },
1038
+ { pattern: '^VBOX.*', manufacturer: 'VirtualBox' },
1039
+ { pattern: 'CORSAIR.*', manufacturer: 'Corsair Components' },
1040
+ { pattern: 'CRUCIAL.*', manufacturer: 'Crucial' },
1041
+ { pattern: 'ECM.*', manufacturer: 'ECM' },
1042
+ { pattern: 'INTEL.*', manufacturer: 'INTEL' },
1043
+ { pattern: 'EVO.*', manufacturer: 'Samsung' },
1044
+ { pattern: 'APPLE.*', manufacturer: 'Apple' },
1045
+ ];
1046
+
1047
+ let result = '';
1048
+ if (model) {
1049
+ model = model.toUpperCase();
1050
+ diskManufacturers.forEach((manufacturer) => {
1051
+ const re = RegExp(manufacturer.pattern);
1052
+ if (re.test(model)) { result = manufacturer.manufacturer; }
1053
+ });
1054
+ }
1055
+ return result;
1056
+ }
1057
+
1058
+ return new Promise((resolve) => {
1059
+ process.nextTick(() => {
1060
+
1061
+ const commitResult = res => {
1062
+ for (let i = 0; i < res.length; i++) {
1063
+ delete res[i].BSDName;
1064
+ }
1065
+ if (callback) {
1066
+ callback(res);
1067
+ }
1068
+ resolve(res);
1069
+ };
1070
+
1071
+ let result = [];
1072
+ let cmd = '';
1073
+
1074
+ if (_linux) {
1075
+ let cmdFullSmart = '';
1076
+
1077
+ exec('export LC_ALL=C; lsblk -ablJO 2>/dev/null; unset LC_ALL', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
1078
+ if (!error) {
1079
+ try {
1080
+ const out = stdout.toString().trim();
1081
+ let devices = [];
1082
+ try {
1083
+ const outJSON = JSON.parse(out);
1084
+ if (outJSON && {}.hasOwnProperty.call(outJSON, 'blockdevices')) {
1085
+ 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)); });
1086
+ }
1087
+ } catch (e) {
1088
+ // fallback to older version of lsblk
1089
+ try {
1090
+ 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();
1091
+ let lines = blkStdoutToObject(out2).split('\n');
1092
+ const data = parseBlk(lines);
1093
+ devices = data.filter(item => { return (item.type === 'disk') && item.size > 0 && ((item.model !== null && item.model !== '') || (item.mount === '' && item.label === '' && item.fsType === '')); });
1094
+ } catch (e) {
1095
+ util.noop();
1096
+ }
1097
+ }
1098
+ devices.forEach((device) => {
1099
+ let mediumType = '';
1100
+ const BSDName = '/dev/' + device.name;
1101
+ const logical = device.name;
1102
+ try {
1103
+ mediumType = execSync('cat /sys/block/' + logical + '/queue/rotational 2>/dev/null', util.execOptsLinux).toString().split('\n')[0];
1104
+ } catch (e) {
1105
+ util.noop();
1106
+ }
1107
+ let interfaceType = device.tran ? device.tran.toUpperCase().trim() : '';
1108
+ if (interfaceType === 'NVME') {
1109
+ mediumType = '2';
1110
+ interfaceType = 'PCIe';
1111
+ }
1112
+ result.push({
1113
+ device: BSDName,
1114
+ 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'))))),
1115
+ name: device.model || '',
1116
+ vendor: getVendorFromModel(device.model) || (device.vendor ? device.vendor.trim() : ''),
1117
+ size: device.size || 0,
1118
+ bytesPerSector: null,
1119
+ totalCylinders: null,
1120
+ totalHeads: null,
1121
+ totalSectors: null,
1122
+ totalTracks: null,
1123
+ tracksPerCylinder: null,
1124
+ sectorsPerTrack: null,
1125
+ firmwareRevision: device.rev ? device.rev.trim() : '',
1126
+ serialNum: device.serial ? device.serial.trim() : '',
1127
+ interfaceType: interfaceType,
1128
+ smartStatus: 'unknown',
1129
+ temperature: null,
1130
+ BSDName: BSDName
1131
+ });
1132
+ cmd += `printf "\n${BSDName}|"; smartctl -H ${BSDName} | grep overall;`;
1133
+ cmdFullSmart += `${cmdFullSmart ? 'printf ",";' : ''}smartctl -a -j ${BSDName};`;
1134
+ });
1135
+ } catch (e) {
1136
+ util.noop();
1137
+ }
1138
+ }
1139
+ // check S.M.A.R.T. status
1140
+ if (cmdFullSmart) {
1141
+ exec(cmdFullSmart, { maxBuffer: 1024 * 1024 }, function (error, stdout) {
1142
+ try {
1143
+ const data = JSON.parse(`[${stdout}]`);
1144
+ data.forEach(disk => {
1145
+ const diskBSDName = disk.smartctl.argv[disk.smartctl.argv.length - 1];
1146
+
1147
+ for (let i = 0; i < result.length; i++) {
1148
+ if (result[i].BSDName === diskBSDName) {
1149
+ result[i].smartStatus = (disk.smart_status.passed ? 'Ok' : (disk.smart_status.passed === false ? 'Predicted Failure' : 'unknown'));
1150
+ if (disk.temperature && disk.temperature.current) {
1151
+ result[i].temperature = disk.temperature.current;
1152
+ }
1153
+ result[i].smartData = disk;
1154
+ }
1155
+ }
1156
+ });
1157
+ commitResult(result);
1158
+ } catch (e) {
1159
+ if (cmd) {
1160
+ cmd = cmd + 'printf "\n"';
1161
+ exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) {
1162
+ let lines = stdout.toString().split('\n');
1163
+ lines.forEach(line => {
1164
+ if (line) {
1165
+ let parts = line.split('|');
1166
+ if (parts.length === 2) {
1167
+ let BSDName = parts[0];
1168
+ parts[1] = parts[1].trim();
1169
+ let parts2 = parts[1].split(':');
1170
+ if (parts2.length === 2) {
1171
+ parts2[1] = parts2[1].trim();
1172
+ let status = parts2[1].toLowerCase();
1173
+ for (let i = 0; i < result.length; i++) {
1174
+ if (result[i].BSDName === BSDName) {
1175
+ result[i].smartStatus = (status === 'passed' ? 'Ok' : (status === 'failed!' ? 'Predicted Failure' : 'unknown'));
1176
+ }
1177
+ }
1178
+ }
1179
+ }
1180
+ }
1181
+ });
1182
+ commitResult(result);
1183
+ });
1184
+ } else {
1185
+ commitResult(result);
1186
+ }
1187
+ }
1188
+ });
1189
+ } else {
1190
+ commitResult(result);
1191
+ }
1192
+ });
1193
+ }
1194
+ if (_freebsd || _openbsd || _netbsd) {
1195
+ if (callback) { callback(result); }
1196
+ resolve(result);
1197
+ }
1198
+ if (_sunos) {
1199
+ if (callback) { callback(result); }
1200
+ resolve(result);
1201
+ }
1202
+ if (_darwin) {
1203
+ exec('system_profiler SPSerialATADataType SPNVMeDataType SPUSBDataType', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
1204
+ if (!error) {
1205
+ // split by type:
1206
+ let lines = stdout.toString().split('\n');
1207
+ let linesSATA = [];
1208
+ let linesNVMe = [];
1209
+ let linesUSB = [];
1210
+ let dataType = 'SATA';
1211
+ lines.forEach(line => {
1212
+ if (line === 'NVMExpress:') { dataType = 'NVMe'; }
1213
+ else if (line === 'USB:') { dataType = 'USB'; }
1214
+ else if (line === 'SATA/SATA Express:') { dataType = 'SATA'; }
1215
+ else if (dataType === 'SATA') { linesSATA.push(line); }
1216
+ else if (dataType === 'NVMe') { linesNVMe.push(line); }
1217
+ else if (dataType === 'USB') { linesUSB.push(line); }
1218
+ });
1219
+ try {
1220
+ // Serial ATA Drives
1221
+ let devices = linesSATA.join('\n').split(' Physical Interconnect: ');
1222
+ devices.shift();
1223
+ devices.forEach(function (device) {
1224
+ device = 'InterfaceType: ' + device;
1225
+ let lines = device.split('\n');
1226
+ const mediumType = util.getValue(lines, 'Medium Type', ':', true).trim();
1227
+ const sizeStr = util.getValue(lines, 'capacity', ':', true).trim();
1228
+ const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim();
1229
+ if (sizeStr) {
1230
+ let sizeValue = 0;
1231
+ if (sizeStr.indexOf('(') >= 0) {
1232
+ sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/\s/g, ''));
1233
+ }
1234
+ if (!sizeValue) {
1235
+ sizeValue = parseInt(sizeStr);
1236
+ }
1237
+ if (sizeValue) {
1238
+ const smartStatusString = util.getValue(lines, 'S.M.A.R.T. status', ':', true).trim().toLowerCase();
1239
+ result.push({
1240
+ device: BSDName,
1241
+ type: mediumType.startsWith('Solid') ? 'SSD' : 'HD',
1242
+ name: util.getValue(lines, 'Model', ':', true).trim(),
1243
+ vendor: getVendorFromModel(util.getValue(lines, 'Model', ':', true).trim()) || util.getValue(lines, 'Manufacturer', ':', true),
1244
+ size: sizeValue,
1245
+ bytesPerSector: null,
1246
+ totalCylinders: null,
1247
+ totalHeads: null,
1248
+ totalSectors: null,
1249
+ totalTracks: null,
1250
+ tracksPerCylinder: null,
1251
+ sectorsPerTrack: null,
1252
+ firmwareRevision: util.getValue(lines, 'Revision', ':', true).trim(),
1253
+ serialNum: util.getValue(lines, 'Serial Number', ':', true).trim(),
1254
+ interfaceType: util.getValue(lines, 'InterfaceType', ':', true).trim(),
1255
+ smartStatus: smartStatusString === 'verified' ? 'OK' : smartStatusString || 'unknown',
1256
+ temperature: null,
1257
+ BSDName: BSDName
1258
+ });
1259
+ cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
1260
+ }
1261
+ }
1262
+ });
1263
+ } catch (e) {
1264
+ util.noop();
1265
+ }
1266
+
1267
+ // NVME Drives
1268
+ try {
1269
+ let devices = linesNVMe.join('\n').split('\n\n Capacity:');
1270
+ devices.shift();
1271
+ devices.forEach(function (device) {
1272
+ device = '!Capacity: ' + device;
1273
+ let lines = device.split('\n');
1274
+ const linkWidth = util.getValue(lines, 'link width', ':', true).trim();
1275
+ const sizeStr = util.getValue(lines, '!capacity', ':', true).trim();
1276
+ const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim();
1277
+ if (sizeStr) {
1278
+ let sizeValue = 0;
1279
+ if (sizeStr.indexOf('(') >= 0) {
1280
+ sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/\s/g, ''));
1281
+ }
1282
+ if (!sizeValue) {
1283
+ sizeValue = parseInt(sizeStr);
1284
+ }
1285
+ if (sizeValue) {
1286
+ const smartStatusString = util.getValue(lines, 'S.M.A.R.T. status', ':', true).trim().toLowerCase();
1287
+ result.push({
1288
+ device: BSDName,
1289
+ type: 'NVMe',
1290
+ name: util.getValue(lines, 'Model', ':', true).trim(),
1291
+ vendor: getVendorFromModel(util.getValue(lines, 'Model', ':', true).trim()),
1292
+ size: sizeValue,
1293
+ bytesPerSector: null,
1294
+ totalCylinders: null,
1295
+ totalHeads: null,
1296
+ totalSectors: null,
1297
+ totalTracks: null,
1298
+ tracksPerCylinder: null,
1299
+ sectorsPerTrack: null,
1300
+ firmwareRevision: util.getValue(lines, 'Revision', ':', true).trim(),
1301
+ serialNum: util.getValue(lines, 'Serial Number', ':', true).trim(),
1302
+ interfaceType: ('PCIe ' + linkWidth).trim(),
1303
+ smartStatus: smartStatusString === 'verified' ? 'OK' : smartStatusString || 'unknown',
1304
+ temperature: null,
1305
+ BSDName: BSDName
1306
+ });
1307
+ cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
1308
+ }
1309
+ }
1310
+ });
1311
+ } catch (e) {
1312
+ util.noop();
1313
+ }
1314
+ // USB Drives
1315
+ try {
1316
+ let devices = linesUSB.join('\n').replaceAll('Media:\n ', 'Model:').split('\n\n Product ID:');
1317
+ devices.shift();
1318
+ devices.forEach(function (device) {
1319
+ let lines = device.split('\n');
1320
+ const sizeStr = util.getValue(lines, 'Capacity', ':', true).trim();
1321
+ const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim();
1322
+ if (sizeStr) {
1323
+ let sizeValue = 0;
1324
+ if (sizeStr.indexOf('(') >= 0) {
1325
+ sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/\s/g, ''));
1326
+ }
1327
+ if (!sizeValue) {
1328
+ sizeValue = parseInt(sizeStr);
1329
+ }
1330
+ if (sizeValue) {
1331
+ const smartStatusString = util.getValue(lines, 'S.M.A.R.T. status', ':', true).trim().toLowerCase();
1332
+ result.push({
1333
+ device: BSDName,
1334
+ type: 'USB',
1335
+ name: util.getValue(lines, 'Model', ':', true).trim().replaceAll(':', ''),
1336
+ vendor: getVendorFromModel(util.getValue(lines, 'Model', ':', true).trim()),
1337
+ size: sizeValue,
1338
+ bytesPerSector: null,
1339
+ totalCylinders: null,
1340
+ totalHeads: null,
1341
+ totalSectors: null,
1342
+ totalTracks: null,
1343
+ tracksPerCylinder: null,
1344
+ sectorsPerTrack: null,
1345
+ firmwareRevision: util.getValue(lines, 'Revision', ':', true).trim(),
1346
+ serialNum: util.getValue(lines, 'Serial Number', ':', true).trim(),
1347
+ interfaceType: 'USB',
1348
+ smartStatus: smartStatusString === 'verified' ? 'OK' : smartStatusString || 'unknown',
1349
+ temperature: null,
1350
+ BSDName: BSDName
1351
+ });
1352
+ cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
1353
+ }
1354
+ }
1355
+ });
1356
+ } catch (e) {
1357
+ util.noop();
1358
+ }
1359
+ if (cmd) {
1360
+ cmd = cmd + 'printf "\n"';
1361
+ exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) {
1362
+ let lines = stdout.toString().split('\n');
1363
+ lines.forEach(line => {
1364
+ if (line) {
1365
+ let parts = line.split('|');
1366
+ if (parts.length === 2) {
1367
+ let BSDName = parts[0];
1368
+ parts[1] = parts[1].trim();
1369
+ let parts2 = parts[1].split(':');
1370
+ if (parts2.length === 2) {
1371
+ parts2[1] = parts2[1].trim();
1372
+ let status = parts2[1].toLowerCase();
1373
+ for (let i = 0; i < result.length; i++) {
1374
+ if (result[i].BSDName === BSDName) {
1375
+ result[i].smartStatus = (status === 'not supported' ? 'not supported' : (status === 'verified' ? 'Ok' : (status === 'failing' ? 'Predicted Failure' : 'unknown')));
1376
+ }
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+ });
1382
+ for (let i = 0; i < result.length; i++) {
1383
+ delete result[i].BSDName;
1384
+ }
1385
+ if (callback) {
1386
+ callback(result);
1387
+ }
1388
+ resolve(result);
1389
+ });
1390
+ } else {
1391
+ for (let i = 0; i < result.length; i++) {
1392
+ delete result[i].BSDName;
1393
+ }
1394
+ if (callback) {
1395
+ callback(result);
1396
+ }
1397
+ resolve(result);
1398
+ }
1399
+ }
1400
+ });
1401
+ }
1402
+ if (_windows) {
1403
+ try {
1404
+ const workload = [];
1405
+ 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'));
1406
+ workload.push(util.powerShell('Get-PhysicalDisk | select BusType,MediaType,FriendlyName,Model,SerialNumber,Size | fl'));
1407
+ if (util.smartMonToolsInstalled()) {
1408
+ try {
1409
+ const smartDev = JSON.parse(execSync('smartctl --scan -j').toString());
1410
+ if (smartDev && smartDev.devices && smartDev.devices.length > 0) {
1411
+ smartDev.devices.forEach((dev) => {
1412
+ workload.push(execPromiseSave(`smartctl -j -a ${dev.name}`, util.execOptsWin));
1413
+ });
1414
+ }
1415
+ } catch (e) {
1416
+ util.noop();
1417
+ }
1418
+ }
1419
+ util.promiseAll(
1420
+ workload
1421
+ ).then((data) => {
1422
+ let devices = data.results[0].toString().split(/\n\s*\n/);
1423
+ devices.forEach(function (device) {
1424
+ let lines = device.split('\r\n');
1425
+ const size = util.getValue(lines, 'Size', ':').trim();
1426
+ const status = util.getValue(lines, 'Status', ':').trim().toLowerCase();
1427
+ if (size) {
1428
+ result.push({
1429
+ device: util.getValue(lines, 'DeviceId', ':'), // changed from PNPDeviceId to DeviceID (be be able to match devices)
1430
+ type: device.indexOf('SSD') > -1 ? 'SSD' : 'HD', // just a starting point ... better: MSFT_PhysicalDisk - Media Type ... see below
1431
+ name: util.getValue(lines, 'Caption', ':'),
1432
+ vendor: getVendorFromModel(util.getValue(lines, 'Caption', ':', true).trim()),
1433
+ size: parseInt(size),
1434
+ bytesPerSector: parseInt(util.getValue(lines, 'BytesPerSector', ':')),
1435
+ totalCylinders: parseInt(util.getValue(lines, 'TotalCylinders', ':')),
1436
+ totalHeads: parseInt(util.getValue(lines, 'TotalHeads', ':')),
1437
+ totalSectors: parseInt(util.getValue(lines, 'TotalSectors', ':')),
1438
+ totalTracks: parseInt(util.getValue(lines, 'TotalTracks', ':')),
1439
+ tracksPerCylinder: parseInt(util.getValue(lines, 'TracksPerCylinder', ':')),
1440
+ sectorsPerTrack: parseInt(util.getValue(lines, 'SectorsPerTrack', ':')),
1441
+ firmwareRevision: util.getValue(lines, 'FirmwareRevision', ':').trim(),
1442
+ serialNum: util.getValue(lines, 'SerialNumber', ':').trim(),
1443
+ interfaceType: util.getValue(lines, 'InterfaceType', ':').trim(),
1444
+ smartStatus: (status === 'ok' ? 'Ok' : (status === 'degraded' ? 'Degraded' : (status === 'pred fail' ? 'Predicted Failure' : 'Unknown'))),
1445
+ temperature: null,
1446
+ });
1447
+ }
1448
+ });
1449
+ devices = data.results[1].split(/\n\s*\n/);
1450
+ devices.forEach(function (device) {
1451
+ let lines = device.split('\r\n');
1452
+ const serialNum = util.getValue(lines, 'SerialNumber', ':').trim();
1453
+ const name = util.getValue(lines, 'FriendlyName', ':').trim().replace('Msft ', 'Microsoft');
1454
+ const size = util.getValue(lines, 'Size', ':').trim();
1455
+ const model = util.getValue(lines, 'Model', ':').trim();
1456
+ const interfaceType = util.getValue(lines, 'BusType', ':').trim();
1457
+ let mediaType = util.getValue(lines, 'MediaType', ':').trim();
1458
+ if (mediaType === '3' || mediaType === 'HDD') { mediaType = 'HD'; }
1459
+ if (mediaType === '4') { mediaType = 'SSD'; }
1460
+ if (mediaType === '5') { mediaType = 'SCM'; }
1461
+ if (mediaType === 'Unspecified' && (model.toLowerCase().indexOf('virtual') > -1 || model.toLowerCase().indexOf('vbox') > -1)) { mediaType = 'Virtual'; }
1462
+ if (size) {
1463
+ let i = util.findObjectByKey(result, 'serialNum', serialNum);
1464
+ if (i === -1 || serialNum === '') {
1465
+ i = util.findObjectByKey(result, 'name', name);
1466
+ }
1467
+ if (i != -1) {
1468
+ result[i].type = mediaType;
1469
+ result[i].interfaceType = interfaceType;
1470
+ }
1471
+ }
1472
+ });
1473
+ // S.M.A.R.T
1474
+ data.results.shift();
1475
+ data.results.shift();
1476
+ if (data.results.length) {
1477
+ data.results.forEach((smartStr) => {
1478
+ try {
1479
+ const smartData = JSON.parse(smartStr);
1480
+ if (smartData.serial_number) {
1481
+ const serialNum = smartData.serial_number;
1482
+ let i = util.findObjectByKey(result, 'serialNum', serialNum);
1483
+ if (i != -1) {
1484
+ result[i].smartStatus = (smartData.smart_status && smartData.smart_status.passed ? 'Ok' : (smartData.smart_status && smartData.smart_status.passed === false ? 'Predicted Failure' : 'unknown'));
1485
+ if (smartData.temperature && smartData.temperature.current) {
1486
+ result[i].temperature = smartData.temperature.current;
1487
+ }
1488
+ result[i].smartData = smartData;
1489
+ }
1490
+ }
1491
+ } catch (e) {
1492
+ util.noop();
1493
+ }
1494
+ });
1495
+ }
1496
+ if (callback) {
1497
+ callback(result);
1498
+ }
1499
+ resolve(result);
1500
+ });
1501
+ } catch (e) {
1502
+ if (callback) { callback(result); }
1503
+ resolve(result);
1504
+ }
1505
+ }
1506
+ });
1507
+ });
1508
+ }
1509
+
1510
+ exports.diskLayout = diskLayout;