UNPKG

39.5 kBJavaScriptView Raw
1'use strict';
2// @ts-check
3// ==================================================================================
4// processes.js
5// ----------------------------------------------------------------------------------
6// Description: System Information - library
7// for Node.js
8// Copyright: (c) 2014 - 2020
9// Author: Sebastian Hildebrandt
10// ----------------------------------------------------------------------------------
11// License: MIT
12// ==================================================================================
13// 10. Processes
14// ----------------------------------------------------------------------------------
15
16const os = require('os');
17const fs = require('fs');
18const path = require('path');
19const exec = require('child_process').exec;
20const execSync = require('child_process').execSync;
21
22const util = require('./util');
23
24let _platform = process.platform;
25
26const _linux = (_platform === 'linux');
27const _darwin = (_platform === 'darwin');
28const _windows = (_platform === 'win32');
29const _freebsd = (_platform === 'freebsd');
30const _openbsd = (_platform === 'openbsd');
31const _netbsd = (_platform === 'netbsd');
32const _sunos = (_platform === 'sunos');
33
34const _processes_cpu = {
35 all: 0,
36 list: {},
37 ms: 0,
38 result: {}
39};
40const _services_cpu = {
41 all: 0,
42 list: {},
43 ms: 0,
44 result: {}
45};
46const _process_cpu = {
47 all: 0,
48 list: {},
49 ms: 0,
50 result: {}
51};
52
53const _winStatusValues = {
54 '0': 'unknown',
55 '1': 'other',
56 '2': 'ready',
57 '3': 'running',
58 '4': 'blocked',
59 '5': 'suspended blocked',
60 '6': 'suspended ready',
61 '7': 'terminated',
62 '8': 'stopped',
63 '9': 'growing',
64};
65
66
67function parseTimeWin(time) {
68 time = time || '';
69 if (time) {
70 return (time.substr(0, 4) + '-' + time.substr(4, 2) + '-' + time.substr(6, 2) + ' ' + time.substr(8, 2) + ':' + time.substr(10, 2) + ':' + time.substr(12, 2));
71 } else {
72 return '';
73 }
74}
75
76function parseTimeUnix(time) {
77 let result = time;
78 let parts = time.replace(/ +/g, ' ').split(' ');
79 if (parts.length === 5) {
80 result = parts[4] + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(parts[1].toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + parts[2]).slice(-2) + ' ' + parts[3];
81 }
82 return result;
83}
84
85// --------------------------
86// PS - services
87// pass a comma separated string with services to check (mysql, apache, postgresql, ...)
88// this function gives an array back, if the services are running.
89
90function services(srv, callback) {
91
92 // fallback - if only callback is given
93 if (util.isFunction(srv) && !callback) {
94 callback = srv;
95 srv = '';
96 }
97
98 return new Promise((resolve) => {
99 process.nextTick(() => {
100 if (srv) {
101 let srvString = util.sanitizeShellString(srv);
102 srvString = srvString.trim().toLowerCase().replace(/,+/g, ' ').replace(/ +/g, ' ').replace(/ +/g, '|');
103 if (srvString === '') {
104 srvString = '*';
105 }
106 let srvs = srvString.split('|');
107 let result = [];
108 let dataSrv = [];
109 let allSrv = [];
110
111 if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
112 if ((_linux || _freebsd || _openbsd || _netbsd) && srvString === '*') {
113 srvString = '';
114 let tmpsrv = execSync('service --status-all 2> /dev/null').toString().split('\n');
115 for (const s of tmpsrv) {
116 const parts = s.split(']');
117 if (parts.length === 2) {
118 srvString += (srvString !== '' ? '|' : '') + parts[1].trim();
119 allSrv.push({ name: parts[1].trim(), running: parts[0].indexOf('+') > 0 });
120 }
121 }
122 srvs = srvString.split('|');
123 }
124 let comm = (_darwin) ? 'ps -caxo pcpu,pmem,pid,command' : 'ps -axo pcpu,pmem,pid,command';
125 if (srvString !== '' && srvs.length > 0) {
126 exec(comm + ' | grep -v grep | grep -iE "' + srvString + '"', { maxBuffer: 1024 * 20000 }, function (error, stdout) {
127 if (!error) {
128 let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
129 srvs.forEach(function (srv) {
130 let ps;
131 if (_darwin) {
132 ps = lines.filter(function (e) {
133 return (e.toLowerCase().indexOf(srv) !== -1);
134 });
135
136 } else {
137 ps = lines.filter(function (e) {
138 return (e.toLowerCase().indexOf(' ' + srv + ':') !== -1) || (e.toLowerCase().indexOf('/' + srv) !== -1);
139 });
140 }
141 let singleSrv = allSrv.filter(item => { return item.name === srv; });
142 const pids = [];
143 for (const p of ps) {
144 const pid = p.trim().split(' ')[2];
145 if (pid) {
146 pids.push(parseInt(pid, 10));
147 }
148 }
149 result.push({
150 name: srv,
151 running: (allSrv.length && singleSrv.length ? singleSrv[0].running : ps.length > 0),
152 startmode: '',
153 pids: pids,
154 pcpu: parseFloat((ps.reduce(function (pv, cv) {
155 return pv + parseFloat(cv.trim().split(' ')[0]);
156 }, 0)).toFixed(2)),
157 pmem: parseFloat((ps.reduce(function (pv, cv) {
158 return pv + parseFloat(cv.trim().split(' ')[1]);
159 }, 0)).toFixed(2))
160 });
161 });
162 if (_linux) {
163 // calc process_cpu - ps is not accurate in linux!
164 let cmd = 'cat /proc/stat | grep "cpu "';
165 for (let i in result) {
166 for (let j in result[i].pids) {
167 cmd += (';cat /proc/' + result[i].pids[j] + '/stat');
168 }
169 }
170 exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
171 let curr_processes = stdout.toString().split('\n');
172
173 // first line (all - /proc/stat)
174 let all = parseProcStat(curr_processes.shift());
175
176 // process
177 let list_new = {};
178 let resultProcess = {};
179 for (let i = 0; i < curr_processes.length; i++) {
180 resultProcess = calcProcStatLinux(curr_processes[i], all, _services_cpu);
181
182 if (resultProcess.pid) {
183 let listPos = -1;
184 for (let i in result) {
185 for (let j in result[i].pids) {
186 if (parseInt(result[i].pids[j]) === parseInt(resultProcess.pid)) {
187 listPos = i;
188 }
189 }
190 }
191 if (listPos >= 0) {
192 result[listPos].pcpu += resultProcess.pcpuu + resultProcess.pcpus;
193 }
194
195 // save new values
196 list_new[resultProcess.pid] = {
197 pcpuu: resultProcess.pcpuu,
198 pcpus: resultProcess.pcpus,
199 utime: resultProcess.utime,
200 stime: resultProcess.stime,
201 cutime: resultProcess.cutime,
202 cstime: resultProcess.cstime
203 };
204 }
205 }
206
207 // store old values
208 _services_cpu.all = all;
209 // _services_cpu.list = list_new;
210 _services_cpu.list = Object.assign({}, list_new);
211 _services_cpu.ms = Date.now() - _services_cpu.ms;
212 // _services_cpu.result = result;
213 _services_cpu.result = Object.assign({}, result);
214 if (callback) { callback(result); }
215 resolve(result);
216 });
217 } else {
218 if (callback) { callback(result); }
219 resolve(result);
220 }
221 } else {
222 exec('ps -o comm | grep -v grep | egrep "' + srvString + '"', { maxBuffer: 1024 * 20000 }, function (error, stdout) {
223 if (!error) {
224 let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
225 srvs.forEach(function (srv) {
226 let ps = lines.filter(function (e) {
227 return e.indexOf(srv) !== -1;
228 });
229 result.push({
230 name: srv,
231 running: ps.length > 0,
232 startmode: '',
233 pcpu: 0,
234 pmem: 0
235 });
236 });
237 if (callback) { callback(result); }
238 resolve(result);
239 } else {
240 srvs.forEach(function (srv) {
241 result.push({
242 name: srv,
243 running: false,
244 startmode: '',
245 pcpu: 0,
246 pmem: 0
247 });
248 });
249 if (callback) { callback(result); }
250 resolve(result);
251 }
252 });
253 }
254 });
255 } else {
256 if (callback) { callback(result); }
257 resolve(result);
258 }
259 }
260 if (_windows) {
261 try {
262 util.wmic('service get /value').then((stdout, error) => {
263 if (!error) {
264 let serviceSections = stdout.split(/\n\s*\n/);
265 for (let i = 0; i < serviceSections.length; i++) {
266 if (serviceSections[i].trim() !== '') {
267 let lines = serviceSections[i].trim().split('\r\n');
268 let srvName = util.getValue(lines, 'Name', '=', true).toLowerCase();
269 let started = util.getValue(lines, 'Started', '=', true);
270 let startMode = util.getValue(lines, 'StartMode', '=', true);
271 let pid = util.getValue(lines, 'ProcessId', '=', true);
272 if (srvString === '*' || srvs.indexOf(srvName) >= 0) {
273 result.push({
274 name: srvName,
275 running: (started === 'TRUE'),
276 startmode: startMode,
277 pids: [pid],
278 pcpu: 0,
279 pmem: 0
280 });
281 dataSrv.push(srvName);
282 }
283 }
284 }
285 if (srvString !== '*') {
286 let srvsMissing = srvs.filter(function (e) {
287 return dataSrv.indexOf(e) === -1;
288 });
289 srvsMissing.forEach(function (srvName) {
290 result.push({
291 name: srvName,
292 running: false,
293 startmode: '',
294 pids: [],
295 pcpu: 0,
296 pmem: 0
297 });
298 });
299 }
300 if (callback) { callback(result); }
301 resolve(result);
302 } else {
303 srvs.forEach(function (srvName) {
304 result.push({
305 name: srvName,
306 running: false,
307 startmode: '',
308 pcpu: 0,
309 pmem: 0
310 });
311 });
312 if (callback) { callback(result); }
313 resolve(result);
314 }
315 });
316 } catch (e) {
317 if (callback) { callback(result); }
318 resolve(result);
319 }
320 }
321 } else {
322 if (callback) { callback({}); }
323 resolve({});
324 }
325 });
326 });
327}
328
329exports.services = services;
330
331function parseProcStat(line) {
332 let parts = line.replace(/ +/g, ' ').split(' ');
333 let user = (parts.length >= 2 ? parseInt(parts[1]) : 0);
334 let nice = (parts.length >= 3 ? parseInt(parts[2]) : 0);
335 let system = (parts.length >= 4 ? parseInt(parts[3]) : 0);
336 let idle = (parts.length >= 5 ? parseInt(parts[4]) : 0);
337 let iowait = (parts.length >= 6 ? parseInt(parts[5]) : 0);
338 let irq = (parts.length >= 7 ? parseInt(parts[6]) : 0);
339 let softirq = (parts.length >= 8 ? parseInt(parts[7]) : 0);
340 let steal = (parts.length >= 9 ? parseInt(parts[8]) : 0);
341 let guest = (parts.length >= 10 ? parseInt(parts[9]) : 0);
342 let guest_nice = (parts.length >= 11 ? parseInt(parts[10]) : 0);
343 return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
344}
345
346function calcProcStatLinux(line, all, _cpu_old) {
347 let statparts = line.replace(/ +/g, ' ').split(')');
348 if (statparts.length >= 2) {
349 let parts = statparts[1].split(' ');
350 if (parts.length >= 16) {
351 let pid = parseInt(statparts[0].split(' ')[0]);
352 let utime = parseInt(parts[12]);
353 let stime = parseInt(parts[13]);
354 let cutime = parseInt(parts[14]);
355 let cstime = parseInt(parts[15]);
356
357 // calc
358 let pcpuu = 0;
359 let pcpus = 0;
360 if (_cpu_old.all > 0 && _cpu_old.list[pid]) {
361 pcpuu = (utime + cutime - _cpu_old.list[pid].utime - _cpu_old.list[pid].cutime) / (all - _cpu_old.all) * 100; // user
362 pcpus = (stime + cstime - _cpu_old.list[pid].stime - _cpu_old.list[pid].cstime) / (all - _cpu_old.all) * 100; // system
363 } else {
364 pcpuu = (utime + cutime) / (all) * 100; // user
365 pcpus = (stime + cstime) / (all) * 100; // system
366 }
367 return {
368 pid: pid,
369 utime: utime,
370 stime: stime,
371 cutime: cutime,
372 cstime: cstime,
373 pcpuu: pcpuu,
374 pcpus: pcpus
375 };
376 } else {
377 return {
378 pid: 0,
379 utime: 0,
380 stime: 0,
381 cutime: 0,
382 cstime: 0,
383 pcpuu: 0,
384 pcpus: 0
385 };
386 }
387 } else {
388 return {
389 pid: 0,
390 utime: 0,
391 stime: 0,
392 cutime: 0,
393 cstime: 0,
394 pcpuu: 0,
395 pcpus: 0
396 };
397 }
398}
399
400function calcProcStatWin(procStat, all, _cpu_old) {
401 // calc
402 let pcpuu = 0;
403 let pcpus = 0;
404 if (_cpu_old.all > 0 && _cpu_old.list[procStat.pid]) {
405 pcpuu = (procStat.utime - _cpu_old.list[procStat.pid].utime) / (all - _cpu_old.all) * 100; // user
406 pcpus = (procStat.stime - _cpu_old.list[procStat.pid].stime) / (all - _cpu_old.all) * 100; // system
407 } else {
408 pcpuu = (procStat.utime) / (all) * 100; // user
409 pcpus = (procStat.stime) / (all) * 100; // system
410 }
411 return {
412 pid: procStat.pid,
413 utime: procStat.utime,
414 stime: procStat.stime,
415 pcpuu: pcpuu,
416 pcpus: pcpus
417 };
418}
419
420
421
422// --------------------------
423// running processes
424
425function processes(callback) {
426
427 let parsedhead = [];
428
429 function getName(command) {
430 command = command || '';
431 let result = command.split(' ')[0];
432 if (result.substr(-1) === ':') {
433 result = result.substr(0, result.length - 1);
434 }
435 if (result.substr(0, 1) !== '[') {
436 let parts = result.split('/');
437 if (isNaN(parseInt(parts[parts.length - 1]))) {
438 result = parts[parts.length - 1];
439 } else {
440 result = parts[0];
441 }
442 }
443 return result;
444 }
445
446 function parseLine(line) {
447
448 let offset = 0;
449 let offset2 = 0;
450
451 function checkColumn(i) {
452 offset = offset2;
453 offset2 = line.substring(parsedhead[i].to + offset, 1000).indexOf(' ');
454 }
455
456 checkColumn(0);
457 const pid = parseInt(line.substring(parsedhead[0].from + offset, parsedhead[0].to + offset2));
458 checkColumn(1);
459 const ppid = parseInt(line.substring(parsedhead[1].from + offset, parsedhead[1].to + offset2));
460 checkColumn(2);
461 const pcpu = parseFloat(line.substring(parsedhead[2].from + offset, parsedhead[2].to + offset2).replace(/,/g, '.'));
462 checkColumn(3);
463 const pmem = parseFloat(line.substring(parsedhead[3].from + offset, parsedhead[3].to + offset2).replace(/,/g, '.'));
464 checkColumn(4);
465 const priority = parseInt(line.substring(parsedhead[4].from + offset, parsedhead[4].to + offset2));
466 checkColumn(5);
467 const vsz = parseInt(line.substring(parsedhead[5].from + offset, parsedhead[5].to + offset2));
468 checkColumn(6);
469 const rss = parseInt(line.substring(parsedhead[6].from + offset, parsedhead[6].to + offset2));
470 checkColumn(7);
471 const nice = parseInt(line.substring(parsedhead[7].from + offset, parsedhead[7].to + offset2)) || 0;
472 checkColumn(8);
473 const started = parseTimeUnix(line.substring(parsedhead[8].from + offset, parsedhead[8].to + offset2).trim());
474 checkColumn(9);
475 let state = line.substring(parsedhead[9].from + offset, parsedhead[9].to + offset2).trim();
476 state = (state[0] === 'R' ? 'running' : (state[0] === 'S' ? 'sleeping' : (state[0] === 'T' ? 'stopped' : (state[0] === 'W' ? 'paging' : (state[0] === 'X' ? 'dead' : (state[0] === 'Z' ? 'zombie' : ((state[0] === 'D' || state[0] === 'U') ? 'blocked' : 'unknown')))))));
477 checkColumn(10);
478 let tty = line.substring(parsedhead[10].from + offset, parsedhead[10].to + offset2).trim();
479 if (tty === '?' || tty === '??') tty = '';
480 checkColumn(11);
481 const user = line.substring(parsedhead[11].from + offset, parsedhead[11].to + offset2).trim();
482 checkColumn(12);
483 const fullcommand = line.substring(parsedhead[12].from + offset, parsedhead[12].to + offset2).trim().replace(/\[/g, '').replace(/]/g, '');
484 let cmdPath = '';
485 let command = '';
486 let params = '';
487 // try to figure out where parameter starts
488 let firstParamPos = fullcommand.indexOf(' -');
489 let firstParamPathPos = fullcommand.indexOf(' /');
490 firstParamPos = (firstParamPos >= 0 ? firstParamPos : 10000);
491 firstParamPathPos = (firstParamPathPos >= 0 ? firstParamPathPos : 10000);
492 const firstPos = Math.min(firstParamPos, firstParamPathPos);
493 let tmpCommand = fullcommand.substr(0, firstPos);
494 const tmpParams = fullcommand.substr(firstPos);
495 const lastSlashPos = tmpCommand.lastIndexOf('/');
496 if (lastSlashPos >= 0) {
497 cmdPath = tmpCommand.substr(0, lastSlashPos);
498 tmpCommand = tmpCommand.substr(lastSlashPos + 1);
499 }
500
501 if (firstPos === 10000 && tmpCommand.indexOf(' ') > -1) {
502 const parts = tmpCommand.split(' ');
503 if (fs.existsSync(path.join(cmdPath, parts[0]))) {
504 command = parts.shift();
505 params = (parts.join(' ') + ' ' + tmpParams).trim();
506 } else {
507 command = tmpCommand.trim();
508 params = tmpParams.trim();
509 }
510 } else {
511 command = tmpCommand.trim();
512 params = tmpParams.trim();
513 }
514
515 return ({
516 pid: pid,
517 parentPid: ppid,
518 name: _linux ? getName(command) : command,
519 pcpu: pcpu,
520 pcpuu: 0,
521 pcpus: 0,
522 pmem: pmem,
523 priority: priority,
524 mem_vsz: vsz,
525 mem_rss: rss,
526 nice: nice,
527 started: started,
528 state: state,
529 tty: tty,
530 user: user,
531 command: command,
532 params: params,
533 path: cmdPath
534 });
535 }
536
537 function parseProcesses(lines) {
538 let result = [];
539 if (lines.length > 1) {
540 let head = lines[0];
541 parsedhead = util.parseHead(head, 8);
542 lines.shift();
543 lines.forEach(function (line) {
544 if (line.trim() !== '') {
545 result.push(parseLine(line));
546 }
547 });
548 }
549 return result;
550 }
551 function parseProcesses2(lines) {
552
553 function formatDateTime(time) {
554 const month = ('0' + (time.getMonth() + 1).toString()).substr(-2);
555 const year = time.getFullYear().toString();
556 const day = ('0' + time.getDay().toString()).substr(-2);
557 const hours = time.getHours().toString();
558 const mins = time.getMinutes().toString();
559 const secs = ('0' + time.getSeconds().toString()).substr(-2);
560
561 return (year + '-' + month + '-' + day + ' ' + hours + ':' + mins + ':' + secs);
562 }
563
564 let result = [];
565 lines.forEach(function (line) {
566 if (line.trim() !== '') {
567 line = line.trim().replace(/ +/g, ' ').replace(/,+/g, '.');
568 const parts = line.split(' ');
569 const command = parts.slice(9).join(' ');
570 const pmem = parseFloat((1.0 * parseInt(parts[3]) * 1024 / os.totalmem()).toFixed(1));
571 const elapsed_parts = parts[5].split(':');
572 const started = formatDateTime(new Date(Date.now() - (elapsed_parts.length > 1 ? (elapsed_parts[0] * 60 + elapsed_parts[1]) * 1000 : elapsed_parts[0] * 1000)));
573
574 result.push({
575 pid: parseInt(parts[0]),
576 parentPid: parseInt(parts[1]),
577 name: getName(command),
578 pcpu: 0,
579 pcpuu: 0,
580 pcpus: 0,
581 pmem: pmem,
582 priority: 0,
583 mem_vsz: parseInt(parts[2]),
584 mem_rss: parseInt(parts[3]),
585 nice: parseInt(parts[4]),
586 started: started,
587 state: (parts[6] === 'R' ? 'running' : (parts[6] === 'S' ? 'sleeping' : (parts[6] === 'T' ? 'stopped' : (parts[6] === 'W' ? 'paging' : (parts[6] === 'X' ? 'dead' : (parts[6] === 'Z' ? 'zombie' : ((parts[6] === 'D' || parts[6] === 'U') ? 'blocked' : 'unknown'))))))),
588 tty: parts[7],
589 user: parts[8],
590 command: command
591 });
592 }
593 });
594 return result;
595 }
596
597 return new Promise((resolve) => {
598 process.nextTick(() => {
599 let result = {
600 all: 0,
601 running: 0,
602 blocked: 0,
603 sleeping: 0,
604 unknown: 0,
605 list: []
606 };
607
608 let cmd = '';
609
610 if ((_processes_cpu.ms && Date.now() - _processes_cpu.ms >= 500) || _processes_cpu.ms === 0) {
611 if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
612 if (_linux) cmd = 'export LC_ALL=C; ps -axo pid:11,ppid:11,pcpu:6,pmem:6,pri:5,vsz:11,rss:11,ni:5,lstart:30,state:5,tty:15,user:20,command; unset LC_ALL';
613 if (_freebsd || _openbsd || _netbsd) cmd = 'export LC_ALL=C; ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,ni,lstart,state,tty,user,command; unset LC_ALL';
614 if (_darwin) cmd = 'export LC_ALL=C; ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,nice,lstart,state,tty,user,command -r; unset LC_ALL';
615 if (_sunos) cmd = 'ps -Ao pid,ppid,pcpu,pmem,pri,vsz,rss,nice,stime,s,tty,user,comm';
616 exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
617 if (!error) {
618 result.list = (parseProcesses(stdout.toString().split('\n'))).slice();
619 result.all = result.list.length;
620 result.running = result.list.filter(function (e) {
621 return e.state === 'running';
622 }).length;
623 result.blocked = result.list.filter(function (e) {
624 return e.state === 'blocked';
625 }).length;
626 result.sleeping = result.list.filter(function (e) {
627 return e.state === 'sleeping';
628 }).length;
629
630 if (_linux) {
631 // calc process_cpu - ps is not accurate in linux!
632 cmd = 'cat /proc/stat | grep "cpu "';
633 for (let i = 0; i < result.list.length; i++) {
634 cmd += (';cat /proc/' + result.list[i].pid + '/stat');
635 }
636 exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
637 let curr_processes = stdout.toString().split('\n');
638
639 // first line (all - /proc/stat)
640 let all = parseProcStat(curr_processes.shift());
641
642 // process
643 let list_new = {};
644 let resultProcess = {};
645 for (let i = 0; i < curr_processes.length; i++) {
646 resultProcess = calcProcStatLinux(curr_processes[i], all, _processes_cpu);
647
648 if (resultProcess.pid) {
649
650 // store pcpu in outer array
651 let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid);
652 if (listPos >= 0) {
653 result.list[listPos].pcpu = resultProcess.pcpuu + resultProcess.pcpus;
654 result.list[listPos].pcpuu = resultProcess.pcpuu;
655 result.list[listPos].pcpus = resultProcess.pcpus;
656 }
657
658 // save new values
659 list_new[resultProcess.pid] = {
660 pcpuu: resultProcess.pcpuu,
661 pcpus: resultProcess.pcpus,
662 utime: resultProcess.utime,
663 stime: resultProcess.stime,
664 cutime: resultProcess.cutime,
665 cstime: resultProcess.cstime
666 };
667 }
668 }
669
670 // store old values
671 _processes_cpu.all = all;
672 // _processes_cpu.list = list_new;
673 _processes_cpu.list = Object.assign({}, list_new);
674 _processes_cpu.ms = Date.now() - _processes_cpu.ms;
675 // _processes_cpu.result = result;
676 _processes_cpu.result = Object.assign({}, result);
677 if (callback) { callback(result); }
678 resolve(result);
679 });
680 } else {
681 if (callback) { callback(result); }
682 resolve(result);
683 }
684 } else {
685 cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,stat,tty,user,comm';
686 if (_sunos) {
687 cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,s,tty,user,comm';
688 }
689 exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
690 if (!error) {
691 let lines = stdout.toString().split('\n');
692 lines.shift();
693
694 result.list = parseProcesses2(lines).slice();
695 result.all = result.list.length;
696 result.running = result.list.filter(function (e) {
697 return e.state === 'running';
698 }).length;
699 result.blocked = result.list.filter(function (e) {
700 return e.state === 'blocked';
701 }).length;
702 result.sleeping = result.list.filter(function (e) {
703 return e.state === 'sleeping';
704 }).length;
705 if (callback) { callback(result); }
706 resolve(result);
707 } else {
708 if (callback) { callback(result); }
709 resolve(result);
710 }
711 });
712 }
713 });
714 } else if (_windows) {
715 try {
716 util.wmic('process get /value').then((stdout, error) => {
717 if (!error) {
718 let processSections = stdout.split(/\n\s*\n/);
719 let procs = [];
720 let procStats = [];
721 let list_new = {};
722 let allcpuu = 0;
723 let allcpus = 0;
724 for (let i = 0; i < processSections.length; i++) {
725 if (processSections[i].trim() !== '') {
726 let lines = processSections[i].trim().split('\r\n');
727 let pid = parseInt(util.getValue(lines, 'ProcessId', '=', true), 10);
728 let parentPid = parseInt(util.getValue(lines, 'ParentProcessId', '=', true), 10);
729 let statusValue = util.getValue(lines, 'ExecutionState', '=');
730 let name = util.getValue(lines, 'Caption', '=', true);
731 let commandLine = util.getValue(lines, 'CommandLine', '=', true);
732 let commandPath = util.getValue(lines, 'ExecutablePath', '=', true);
733 let utime = parseInt(util.getValue(lines, 'UserModeTime', '=', true), 10);
734 let stime = parseInt(util.getValue(lines, 'KernelModeTime', '=', true), 10);
735 let mem = parseInt(util.getValue(lines, 'WorkingSetSize', '=', true), 10);
736 allcpuu = allcpuu + utime;
737 allcpus = allcpus + stime;
738 result.all++;
739 if (!statusValue) { result.unknown++; }
740 if (statusValue === '3') { result.running++; }
741 if (statusValue === '4' || statusValue === '5') { result.blocked++; }
742
743 procStats.push({
744 pid: pid,
745 utime: utime,
746 stime: stime,
747 pcpu: 0,
748 pcpuu: 0,
749 pcpus: 0,
750 });
751 procs.push({
752 pid: pid,
753 parentPid: parentPid,
754 name: name,
755 pcpu: 0,
756 pcpuu: 0,
757 pcpus: 0,
758 pmem: mem / os.totalmem() * 100,
759 priority: parseInt(util.getValue(lines, 'Priority', '=', true), 10),
760 mem_vsz: parseInt(util.getValue(lines, 'PageFileUsage', '=', true), 10),
761 mem_rss: Math.floor(parseInt(util.getValue(lines, 'WorkingSetSize', '=', true), 10) / 1024),
762 nice: 0,
763 started: parseTimeWin(util.getValue(lines, 'CreationDate', '=', true)),
764 state: (!statusValue ? _winStatusValues[0] : _winStatusValues[statusValue]),
765 tty: '',
766 user: '',
767 command: commandLine || name,
768 path: commandPath,
769 params: ''
770 });
771 }
772 }
773 result.sleeping = result.all - result.running - result.blocked - result.unknown;
774 result.list = procs;
775 for (let i = 0; i < procStats.length; i++) {
776 let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _processes_cpu);
777
778 // store pcpu in outer array
779 let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid);
780 if (listPos >= 0) {
781 result.list[listPos].pcpu = resultProcess.pcpuu + resultProcess.pcpus;
782 result.list[listPos].pcpuu = resultProcess.pcpuu;
783 result.list[listPos].pcpus = resultProcess.pcpus;
784 }
785
786 // save new values
787 list_new[resultProcess.pid] = {
788 pcpuu: resultProcess.pcpuu,
789 pcpus: resultProcess.pcpus,
790 utime: resultProcess.utime,
791 stime: resultProcess.stime
792 };
793 }
794 // store old values
795 _processes_cpu.all = allcpuu + allcpus;
796 // _processes_cpu.list = list_new;
797 _processes_cpu.list = Object.assign({}, list_new);
798 _processes_cpu.ms = Date.now() - _processes_cpu.ms;
799 // _processes_cpu.result = result;
800 _processes_cpu.result = Object.assign({}, result);
801 }
802 if (callback) {
803 callback(result);
804 }
805 resolve(result);
806 });
807 } catch (e) {
808 if (callback) { callback(result); }
809 resolve(result);
810 }
811 } else {
812 if (callback) { callback(result); }
813 resolve(result);
814 }
815 } else {
816 if (callback) { callback(_processes_cpu.result); }
817 resolve(_processes_cpu.result);
818 }
819 });
820 });
821}
822
823exports.processes = processes;
824
825// --------------------------
826// PS - process load
827// get detailed information about a certain process
828// (PID, CPU-Usage %, Mem-Usage %)
829
830function processLoad(proc, callback) {
831
832 // fallback - if only callback is given
833 if (util.isFunction(proc) && !callback) {
834 callback = proc;
835 proc = '';
836 }
837
838 return new Promise((resolve) => {
839 process.nextTick(() => {
840 const procSanitized = util.sanitizeShellString(proc);
841
842 let result = {
843 'proc': procSanitized,
844 'pid': -1,
845 'cpu': 0,
846 'mem': 0
847 };
848
849 if (procSanitized) {
850 if (_windows) {
851 try {
852 util.wmic('process get /value').then((stdout, error) => {
853 if (!error) {
854 let processSections = stdout.split(/\n\s*\n/);
855 let procStats = [];
856 let list_new = {};
857 let allcpuu = 0;
858 let allcpus = 0;
859 for (let i = 0; i < processSections.length; i++) {
860 if (processSections[i].trim() !== '') {
861 let lines = processSections[i].trim().split('\r\n');
862 let pid = parseInt(util.getValue(lines, 'ProcessId', '=', true), 10);
863 let name = util.getValue(lines, 'Caption', '=', true);
864 let utime = parseInt(util.getValue(lines, 'UserModeTime', '=', true), 10);
865 let stime = parseInt(util.getValue(lines, 'KernelModeTime', '=', true), 10);
866 let mem = parseInt(util.getValue(lines, 'WorkingSetSize', '=', true), 10);
867 allcpuu = allcpuu + utime;
868 allcpus = allcpus + stime;
869
870 procStats.push({
871 pid: pid,
872 utime: utime,
873 stime: stime,
874 pcpu: 0,
875 pcpuu: 0,
876 pcpus: 0,
877 });
878 if (name.toLowerCase().indexOf(procSanitized.toLowerCase()) >= 0) {
879 if (result.pid === -1) {
880 result = {
881 proc: name,
882 pid: pid,
883 pids: [pid],
884 cpu: 0,
885 mem: mem / os.totalmem() * 100
886 };
887 } else {
888 result.pids.push(pid);
889 result.mem += mem / os.totalmem() * 100;
890 }
891 }
892 }
893 }
894 for (let i = 0; i < procStats.length; i++) {
895 let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _process_cpu);
896
897 // store pcpu in outer array
898 if (result && result.pids && result.pids.length > 0) {
899 let listPos = result.pids.indexOf(resultProcess.pid);
900 if (listPos >= 0) {
901 result.cpu = resultProcess.pcpuu + resultProcess.pcpus;
902 }
903 }
904
905 // save new values
906 list_new[resultProcess.pid] = {
907 pcpuu: resultProcess.pcpuu,
908 pcpus: resultProcess.pcpus,
909 utime: resultProcess.utime,
910 stime: resultProcess.stime
911 };
912 }
913 // store old values
914 _process_cpu.all = allcpuu + allcpus;
915 // _process_cpu.list = list_new;
916 _process_cpu.list = Object.assign({}, list_new);
917 _process_cpu.ms = Date.now() - _process_cpu.ms;
918 // _process_cpu.result = result;
919 _process_cpu.result = Object.assign({}, result);
920 if (callback) {
921 callback(result);
922 }
923 resolve(result);
924 }
925 });
926 } catch (e) {
927 if (callback) { callback(result); }
928 resolve(result);
929 }
930 }
931
932 if (_darwin || _linux) {
933 exec('ps -axo pid,pcpu,pmem,comm | grep -i ' + procSanitized + ' | grep -v grep', { maxBuffer: 1024 * 20000 }, function (error, stdout) {
934 if (!error) {
935 let lines = stdout.toString().split('\n');
936
937 let pid = 0;
938 let pids = [];
939 let cpu = 0;
940 let mem = 0;
941
942 lines.forEach(function (line) {
943 let data = line.trim().replace(/ +/g, ' ').split(' ');
944 if (data.length > 3) {
945 pid = (!pid ? parseInt(data[0]) : 0);
946 pids.push(parseInt(data[0], 10));
947 cpu = cpu + parseFloat(data[1].replace(',', '.'));
948 mem = mem + parseFloat(data[2].replace(',', '.'));
949 }
950 });
951
952 result = {
953 'proc': procSanitized,
954 'pid': pid,
955 'pids': pids,
956 'cpu': parseFloat((cpu / lines.length).toFixed(2)),
957 'mem': parseFloat((mem / lines.length).toFixed(2))
958 };
959 if (_linux) {
960 // calc process_cpu - ps is not accurate in linux!
961 let cmd = 'cat /proc/stat | grep "cpu "';
962 for (let i = 0; i < result.pids.length; i++) {
963 cmd += (';cat /proc/' + result.pids[i] + '/stat');
964 }
965
966 exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
967 let curr_processes = stdout.toString().split('\n');
968
969 // first line (all - /proc/stat)
970 let all = parseProcStat(curr_processes.shift());
971
972 // process
973 let list_new = {};
974 let resultProcess = {};
975 result.cpu = 0;
976 for (let i = 0; i < curr_processes.length; i++) {
977 resultProcess = calcProcStatLinux(curr_processes[i], all, _process_cpu);
978
979 if (resultProcess.pid) {
980
981 // store pcpu in outer result
982 result.cpu += resultProcess.pcpuu + resultProcess.pcpus;
983
984 // save new values
985 list_new[resultProcess.pid] = {
986 pcpuu: resultProcess.pcpuu,
987 pcpus: resultProcess.pcpus,
988 utime: resultProcess.utime,
989 stime: resultProcess.stime,
990 cutime: resultProcess.cutime,
991 cstime: resultProcess.cstime
992 };
993 }
994 }
995
996 result.cpu = Math.round(result.cpu * 100) / 100;
997
998 _process_cpu.all = all;
999 // _process_cpu.list = list_new;
1000 _process_cpu.list = Object.assign({}, list_new);
1001 _process_cpu.ms = Date.now() - _process_cpu.ms;
1002 // _process_cpu.result = result;
1003 _process_cpu.result = Object.assign({}, result);
1004 if (callback) { callback(result); }
1005 resolve(result);
1006 });
1007 } else {
1008 if (callback) { callback(result); }
1009 resolve(result);
1010 }
1011 } else {
1012 if (callback) { callback(result); }
1013 resolve(result);
1014 }
1015 });
1016 }
1017 }
1018 });
1019 });
1020}
1021
1022exports.processLoad = processLoad;