Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

processes.js 39KB

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