code-poltergeist-system-monitor 1.0.6

Sign up to get free protection for your applications and to get access to all the features.

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;