'use strict'; // @ts-check // ================================================================================== // processes.js // ---------------------------------------------------------------------------------- // Description: System Information - library // for Node.js // Copyright: (c) 2014 - 2022 // Author: Sebastian Hildebrandt // ---------------------------------------------------------------------------------- // License: MIT // ================================================================================== // 10. Processes // ---------------------------------------------------------------------------------- const os = require('os'); const fs = require('fs'); const path = require('path'); const exec = require('child_process').exec; const execSync = require('child_process').execSync; const util = require('./util'); let _platform = process.platform; const _linux = (_platform === 'linux' || _platform === 'android'); const _darwin = (_platform === 'darwin'); const _windows = (_platform === 'win32'); const _freebsd = (_platform === 'freebsd'); const _openbsd = (_platform === 'openbsd'); const _netbsd = (_platform === 'netbsd'); const _sunos = (_platform === 'sunos'); const _processes_cpu = { all: 0, all_utime: 0, all_stime: 0, list: {}, ms: 0, result: {} }; const _services_cpu = { all: 0, all_utime: 0, all_stime: 0, list: {}, ms: 0, result: {} }; const _process_cpu = { all: 0, all_utime: 0, all_stime: 0, list: {}, ms: 0, result: {} }; const _winStatusValues = { '0': 'unknown', '1': 'other', '2': 'ready', '3': 'running', '4': 'blocked', '5': 'suspended blocked', '6': 'suspended ready', '7': 'terminated', '8': 'stopped', '9': 'growing', }; function parseTimeWin(time) { time = time || ''; if (time) { 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)); } else { return ''; } } function parseTimeUnix(time) { let result = time; let parts = time.replace(/ +/g, ' ').split(' '); if (parts.length === 5) { result = parts[4] + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(parts[1].toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + parts[2]).slice(-2) + ' ' + parts[3]; } return result; } // -------------------------- // PS - services // pass a comma separated string with services to check (mysql, apache, postgresql, ...) // this function gives an array back, if the services are running. function services(srv, callback) { // fallback - if only callback is given if (util.isFunction(srv) && !callback) { callback = srv; srv = ''; } return new Promise((resolve) => { process.nextTick(() => { if (typeof srv !== 'string') { if (callback) { callback([]); } return resolve([]); } if (srv) { let srvString = ''; srvString.__proto__.toLowerCase = util.stringToLower; srvString.__proto__.replace = util.stringReplace; srvString.__proto__.trim = util.stringTrim; const s = util.sanitizeShellString(srv); for (let i = 0; i <= util.mathMin(s.length, 2000); i++) { if (!(s[i] === undefined)) { srvString = srvString + s[i]; } } srvString = srvString.trim().toLowerCase().replace(/, /g, '|').replace(/,+/g, '|'); if (srvString === '') { srvString = '*'; } if (util.isPrototypePolluted() && srvString !== '*') { srvString = '------'; } let srvs = srvString.split('|'); let result = []; let dataSrv = []; // let allSrv = []; if (_linux || _freebsd || _openbsd || _netbsd || _darwin) { if ((_linux || _freebsd || _openbsd || _netbsd) && srvString === '*') { try { const tmpsrv = execSync('systemctl --type=service --no-legend 2> /dev/null').toString().split('\n'); srvs = []; for (const s of tmpsrv) { const name = s.split('.service')[0]; if (name) { srvs.push(name); } } srvString = srvs.join('|'); } catch (d) { try { srvString = ''; const tmpsrv = execSync('service --status-all 2> /dev/null').toString().split('\n'); for (const s of tmpsrv) { const parts = s.split(']'); if (parts.length === 2) { srvString += (srvString !== '' ? '|' : '') + parts[1].trim(); // allSrv.push({ name: parts[1].trim(), running: parts[0].indexOf('+') > 0 }); } } srvs = srvString.split('|'); } catch (e) { try { const srvStr = execSync('ls /etc/init.d/ -m 2> /dev/null').toString().split('\n').join(''); srvString = ''; if (srvStr) { const tmpsrv = srvStr.split(','); for (const s of tmpsrv) { const name = s.trim(); if (name) { srvString += (srvString !== '' ? '|' : '') + name; // allSrv.push({ name: name, running: null }); } } srvs = srvString.split('|'); } } catch (f) { // allSrv = []; srvString = ''; srvs = []; } } } } if ((_darwin) && srvString === '*') { // service enumeration not yet suported on mac OS if (callback) { callback(result); } resolve(result); } let args = (_darwin) ? ['-caxo', 'pcpu,pmem,pid,command'] : ['-axo', 'pcpu,pmem,pid,command']; if (srvString !== '' && srvs.length > 0) { util.execSafe('ps', args).then((stdout) => { if (stdout) { let lines = stdout.replace(/ +/g, ' ').replace(/,+/g, '.').split('\n'); srvs.forEach(function (srv) { let ps; if (_darwin) { ps = lines.filter(function (e) { return (e.toLowerCase().indexOf(srv) !== -1); }); } else { ps = lines.filter(function (e) { return (e.toLowerCase().indexOf(' ' + srv + ':') !== -1) || (e.toLowerCase().indexOf('/' + srv) !== -1); }); } // let singleSrv = allSrv.filter(item => { return item.name === srv; }); const pids = []; for (const p of ps) { const pid = p.trim().split(' ')[2]; if (pid) { pids.push(parseInt(pid, 10)); } } result.push({ name: srv, // running: (allSrv.length && singleSrv.length && singleSrv[0].running !== null ? singleSrv[0].running : ps.length > 0), running: ps.length > 0, startmode: '', pids: pids, cpu: parseFloat((ps.reduce(function (pv, cv) { return pv + parseFloat(cv.trim().split(' ')[0]); }, 0)).toFixed(2)), mem: parseFloat((ps.reduce(function (pv, cv) { return pv + parseFloat(cv.trim().split(' ')[1]); }, 0)).toFixed(2)) }); }); if (_linux) { // calc process_cpu - ps is not accurate in linux! let cmd = 'cat /proc/stat | grep "cpu "'; for (let i in result) { for (let j in result[i].pids) { cmd += (';cat /proc/' + result[i].pids[j] + '/stat'); } } exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { let curr_processes = stdout.toString().split('\n'); // first line (all - /proc/stat) let all = parseProcStat(curr_processes.shift()); // process let list_new = {}; let resultProcess = {}; for (let i = 0; i < curr_processes.length; i++) { resultProcess = calcProcStatLinux(curr_processes[i], all, _services_cpu); if (resultProcess.pid) { let listPos = -1; for (let i in result) { for (let j in result[i].pids) { if (parseInt(result[i].pids[j]) === parseInt(resultProcess.pid)) { listPos = i; } } } if (listPos >= 0) { result[listPos].cpu += resultProcess.cpuu + resultProcess.cpus; } // save new values list_new[resultProcess.pid] = { cpuu: resultProcess.cpuu, cpus: resultProcess.cpus, utime: resultProcess.utime, stime: resultProcess.stime, cutime: resultProcess.cutime, cstime: resultProcess.cstime }; } } // store old values _services_cpu.all = all; // _services_cpu.list = list_new; _services_cpu.list = Object.assign({}, list_new); _services_cpu.ms = Date.now() - _services_cpu.ms; // _services_cpu.result = result; _services_cpu.result = Object.assign({}, result); if (callback) { callback(result); } resolve(result); }); } else { if (callback) { callback(result); } resolve(result); } } else { args = ['-o', 'comm']; util.execSafe('ps', args).then((stdout) => { if (stdout) { let lines = stdout.replace(/ +/g, ' ').replace(/,+/g, '.').split('\n'); srvs.forEach(function (srv) { let ps = lines.filter(function (e) { return e.indexOf(srv) !== -1; }); result.push({ name: srv, running: ps.length > 0, startmode: '', cpu: 0, mem: 0 }); }); if (callback) { callback(result); } resolve(result); } else { srvs.forEach(function (srv) { result.push({ name: srv, running: false, startmode: '', cpu: 0, mem: 0 }); }); if (callback) { callback(result); } resolve(result); } }); } }); } else { if (callback) { callback(result); } resolve(result); } } if (_windows) { try { let wincommand = 'Get-WmiObject Win32_Service'; if (srvs[0] !== '*') { wincommand += ' -Filter "'; for (let i = 0; i < srvs.length; i++) { wincommand += `Name='${srvs[i]}' or `; } wincommand = `${wincommand.slice(0, -4)}"`; } wincommand += ' | select Name,Caption,Started,StartMode,ProcessId | fl'; util.powerShell(wincommand).then((stdout, error) => { if (!error) { let serviceSections = stdout.split(/\n\s*\n/); for (let i = 0; i < serviceSections.length; i++) { if (serviceSections[i].trim() !== '') { let lines = serviceSections[i].trim().split('\r\n'); let srvName = util.getValue(lines, 'Name', ':', true).toLowerCase(); let srvCaption = util.getValue(lines, 'Caption', ':', true).toLowerCase(); let started = util.getValue(lines, 'Started', ':', true); let startMode = util.getValue(lines, 'StartMode', ':', true); let pid = util.getValue(lines, 'ProcessId', ':', true); if (srvString === '*' || srvs.indexOf(srvName) >= 0 || srvs.indexOf(srvCaption) >= 0) { result.push({ name: srvName, running: (started.toLowerCase() === 'true'), startmode: startMode, pids: [pid], cpu: 0, mem: 0 }); dataSrv.push(srvName); dataSrv.push(srvCaption); } } } if (srvString !== '*') { let srvsMissing = srvs.filter(function (e) { return dataSrv.indexOf(e) === -1; }); srvsMissing.forEach(function (srvName) { result.push({ name: srvName, running: false, startmode: '', pids: [], cpu: 0, mem: 0 }); }); } if (callback) { callback(result); } resolve(result); } else { srvs.forEach(function (srvName) { result.push({ name: srvName, running: false, startmode: '', cpu: 0, mem: 0 }); }); if (callback) { callback(result); } resolve(result); } }); } catch (e) { if (callback) { callback(result); } resolve(result); } } } else { if (callback) { callback([]); } resolve([]); } }); }); } exports.services = services; function parseProcStat(line) { let parts = line.replace(/ +/g, ' ').split(' '); let user = (parts.length >= 2 ? parseInt(parts[1]) : 0); let nice = (parts.length >= 3 ? parseInt(parts[2]) : 0); let system = (parts.length >= 4 ? parseInt(parts[3]) : 0); let idle = (parts.length >= 5 ? parseInt(parts[4]) : 0); let iowait = (parts.length >= 6 ? parseInt(parts[5]) : 0); let irq = (parts.length >= 7 ? parseInt(parts[6]) : 0); let softirq = (parts.length >= 8 ? parseInt(parts[7]) : 0); let steal = (parts.length >= 9 ? parseInt(parts[8]) : 0); let guest = (parts.length >= 10 ? parseInt(parts[9]) : 0); let guest_nice = (parts.length >= 11 ? parseInt(parts[10]) : 0); return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice; } function calcProcStatLinux(line, all, _cpu_old) { let statparts = line.replace(/ +/g, ' ').split(')'); if (statparts.length >= 2) { let parts = statparts[1].split(' '); if (parts.length >= 16) { let pid = parseInt(statparts[0].split(' ')[0]); let utime = parseInt(parts[12]); let stime = parseInt(parts[13]); let cutime = parseInt(parts[14]); let cstime = parseInt(parts[15]); // calc let cpuu = 0; let cpus = 0; if (_cpu_old.all > 0 && _cpu_old.list[pid]) { cpuu = (utime + cutime - _cpu_old.list[pid].utime - _cpu_old.list[pid].cutime) / (all - _cpu_old.all) * 100; // user cpus = (stime + cstime - _cpu_old.list[pid].stime - _cpu_old.list[pid].cstime) / (all - _cpu_old.all) * 100; // system } else { cpuu = (utime + cutime) / (all) * 100; // user cpus = (stime + cstime) / (all) * 100; // system } return { pid: pid, utime: utime, stime: stime, cutime: cutime, cstime: cstime, cpuu: cpuu, cpus: cpus }; } else { return { pid: 0, utime: 0, stime: 0, cutime: 0, cstime: 0, cpuu: 0, cpus: 0 }; } } else { return { pid: 0, utime: 0, stime: 0, cutime: 0, cstime: 0, cpuu: 0, cpus: 0 }; } } function calcProcStatWin(procStat, all, _cpu_old) { // calc let cpuu = 0; let cpus = 0; if (_cpu_old.all > 0 && _cpu_old.list[procStat.pid]) { cpuu = (procStat.utime - _cpu_old.list[procStat.pid].utime) / (all - _cpu_old.all) * 100; // user cpus = (procStat.stime - _cpu_old.list[procStat.pid].stime) / (all - _cpu_old.all) * 100; // system } else { cpuu = (procStat.utime) / (all) * 100; // user cpus = (procStat.stime) / (all) * 100; // system } return { pid: procStat.pid, utime: cpuu > 0 ? procStat.utime : 0, stime: cpus > 0 ? procStat.stime : 0, cpuu: cpuu > 0 ? cpuu : 0, cpus: cpus > 0 ? cpus : 0 }; } // -------------------------- // running processes function processes(callback) { let parsedhead = []; function getName(command) { command = command || ''; let result = command.split(' ')[0]; if (result.substr(-1) === ':') { result = result.substr(0, result.length - 1); } if (result.substr(0, 1) !== '[') { let parts = result.split('/'); if (isNaN(parseInt(parts[parts.length - 1]))) { result = parts[parts.length - 1]; } else { result = parts[0]; } } return result; } function parseLine(line) { let offset = 0; let offset2 = 0; function checkColumn(i) { offset = offset2; if (parsedhead[i]) { offset2 = line.substring(parsedhead[i].to + offset, 10000).indexOf(' '); } else { offset2 = 10000; } } checkColumn(0); const pid = parseInt(line.substring(parsedhead[0].from + offset, parsedhead[0].to + offset2)); checkColumn(1); const ppid = parseInt(line.substring(parsedhead[1].from + offset, parsedhead[1].to + offset2)); checkColumn(2); const cpu = parseFloat(line.substring(parsedhead[2].from + offset, parsedhead[2].to + offset2).replace(/,/g, '.')); checkColumn(3); const mem = parseFloat(line.substring(parsedhead[3].from + offset, parsedhead[3].to + offset2).replace(/,/g, '.')); checkColumn(4); const priority = parseInt(line.substring(parsedhead[4].from + offset, parsedhead[4].to + offset2)); checkColumn(5); const vsz = parseInt(line.substring(parsedhead[5].from + offset, parsedhead[5].to + offset2)); checkColumn(6); const rss = parseInt(line.substring(parsedhead[6].from + offset, parsedhead[6].to + offset2)); checkColumn(7); const nice = parseInt(line.substring(parsedhead[7].from + offset, parsedhead[7].to + offset2)) || 0; checkColumn(8); const started = parseTimeUnix(line.substring(parsedhead[8].from + offset, parsedhead[8].to + offset2).trim()); checkColumn(9); let state = line.substring(parsedhead[9].from + offset, parsedhead[9].to + offset2).trim(); 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'))))))); checkColumn(10); let tty = line.substring(parsedhead[10].from + offset, parsedhead[10].to + offset2).trim(); if (tty === '?' || tty === '??') { tty = ''; } checkColumn(11); const user = line.substring(parsedhead[11].from + offset, parsedhead[11].to + offset2).trim(); checkColumn(12); let cmdPath = ''; let command = ''; let params = ''; let fullcommand = line.substring(parsedhead[12].from + offset, parsedhead[12].to + offset2).trim(); if (fullcommand.substr(fullcommand.length - 1) === ']') { fullcommand = fullcommand.slice(0, -1); } if (fullcommand.substr(0, 1) === '[') { command = fullcommand.substring(1); } else { // try to figure out where parameter starts let firstParamPos = fullcommand.indexOf(' -'); let firstParamPathPos = fullcommand.indexOf(' /'); firstParamPos = (firstParamPos >= 0 ? firstParamPos : 10000); firstParamPathPos = (firstParamPathPos >= 0 ? firstParamPathPos : 10000); const firstPos = Math.min(firstParamPos, firstParamPathPos); let tmpCommand = fullcommand.substr(0, firstPos); const tmpParams = fullcommand.substr(firstPos); const lastSlashPos = tmpCommand.lastIndexOf('/'); if (lastSlashPos >= 0) { cmdPath = tmpCommand.substr(0, lastSlashPos); tmpCommand = tmpCommand.substr(lastSlashPos + 1); } if (firstPos === 10000 && tmpCommand.indexOf(' ') > -1) { const parts = tmpCommand.split(' '); if (fs.existsSync(path.join(cmdPath, parts[0]))) { command = parts.shift(); params = (parts.join(' ') + ' ' + tmpParams).trim(); } else { command = tmpCommand.trim(); params = tmpParams.trim(); } } else { command = tmpCommand.trim(); params = tmpParams.trim(); } } return ({ pid: pid, parentPid: ppid, name: _linux ? getName(command) : command, cpu: cpu, cpuu: 0, cpus: 0, mem: mem, priority: priority, memVsz: vsz, memRss: rss, nice: nice, started: started, state: state, tty: tty, user: user, command: command, params: params, path: cmdPath }); } function parseProcesses(lines) { let result = []; if (lines.length > 1) { let head = lines[0]; parsedhead = util.parseHead(head, 8); lines.shift(); lines.forEach(function (line) { if (line.trim() !== '') { result.push(parseLine(line)); } }); } return result; } function parseProcesses2(lines) { function formatDateTime(time) { const month = ('0' + (time.getMonth() + 1).toString()).substr(-2); const year = time.getFullYear().toString(); const day = ('0' + time.getDay().toString()).substr(-2); const hours = time.getHours().toString(); const mins = time.getMinutes().toString(); const secs = ('0' + time.getSeconds().toString()).substr(-2); return (year + '-' + month + '-' + day + ' ' + hours + ':' + mins + ':' + secs); } let result = []; lines.forEach(function (line) { if (line.trim() !== '') { line = line.trim().replace(/ +/g, ' ').replace(/,+/g, '.'); const parts = line.split(' '); const command = parts.slice(9).join(' '); const pmem = parseFloat((1.0 * parseInt(parts[3]) * 1024 / os.totalmem()).toFixed(1)); const elapsed_parts = parts[5].split(':'); const started = formatDateTime(new Date(Date.now() - (elapsed_parts.length > 1 ? (elapsed_parts[0] * 60 + elapsed_parts[1]) * 1000 : elapsed_parts[0] * 1000))); result.push({ pid: parseInt(parts[0]), parentPid: parseInt(parts[1]), name: getName(command), cpu: 0, cpuu: 0, cpus: 0, mem: pmem, priority: 0, memVsz: parseInt(parts[2]), memRss: parseInt(parts[3]), nice: parseInt(parts[4]), started: started, 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'))))))), tty: parts[7], user: parts[8], command: command }); } }); return result; } return new Promise((resolve) => { process.nextTick(() => { let result = { all: 0, running: 0, blocked: 0, sleeping: 0, unknown: 0, list: [] }; let cmd = ''; if ((_processes_cpu.ms && Date.now() - _processes_cpu.ms >= 500) || _processes_cpu.ms === 0) { if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) { 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'; } 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'; } if (_darwin) { cmd = 'ps -axo pid,ppid,pcpu,pmem,pri,vsz=xxx_fake_title,rss=fake_title2,nice,lstart,state,tty,user,command -r'; } if (_sunos) { cmd = 'ps -Ao pid,ppid,pcpu,pmem,pri,vsz,rss,nice,stime,s,tty,user,comm'; } exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { if (!error && stdout.toString().trim()) { result.list = (parseProcesses(stdout.toString().split('\n'))).slice(); result.all = result.list.length; result.running = result.list.filter(function (e) { return e.state === 'running'; }).length; result.blocked = result.list.filter(function (e) { return e.state === 'blocked'; }).length; result.sleeping = result.list.filter(function (e) { return e.state === 'sleeping'; }).length; if (_linux) { // calc process_cpu - ps is not accurate in linux! cmd = 'cat /proc/stat | grep "cpu "'; for (let i = 0; i < result.list.length; i++) { cmd += (';cat /proc/' + result.list[i].pid + '/stat'); } exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { let curr_processes = stdout.toString().split('\n'); // first line (all - /proc/stat) let all = parseProcStat(curr_processes.shift()); // process let list_new = {}; let resultProcess = {}; for (let i = 0; i < curr_processes.length; i++) { resultProcess = calcProcStatLinux(curr_processes[i], all, _processes_cpu); if (resultProcess.pid) { // store pcpu in outer array let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid); if (listPos >= 0) { result.list[listPos].cpu = resultProcess.cpuu + resultProcess.cpus; result.list[listPos].cpuu = resultProcess.cpuu; result.list[listPos].cpus = resultProcess.cpus; } // save new values list_new[resultProcess.pid] = { cpuu: resultProcess.cpuu, cpus: resultProcess.cpus, utime: resultProcess.utime, stime: resultProcess.stime, cutime: resultProcess.cutime, cstime: resultProcess.cstime }; } } // store old values _processes_cpu.all = all; // _processes_cpu.list = list_new; _processes_cpu.list = Object.assign({}, list_new); _processes_cpu.ms = Date.now() - _processes_cpu.ms; // _processes_cpu.result = result; _processes_cpu.result = Object.assign({}, result); if (callback) { callback(result); } resolve(result); }); } else { if (callback) { callback(result); } resolve(result); } } else { cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,stat,tty,user,comm'; if (_sunos) { cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,s,tty,user,comm'; } exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); lines.shift(); result.list = parseProcesses2(lines).slice(); result.all = result.list.length; result.running = result.list.filter(function (e) { return e.state === 'running'; }).length; result.blocked = result.list.filter(function (e) { return e.state === 'blocked'; }).length; result.sleeping = result.list.filter(function (e) { return e.state === 'sleeping'; }).length; if (callback) { callback(result); } resolve(result); } else { if (callback) { callback(result); } resolve(result); } }); } }); } else if (_windows) { try { util.powerShell('Get-WmiObject Win32_Process | select ProcessId,ParentProcessId,ExecutionState,Caption,CommandLine,ExecutablePath,UserModeTime,KernelModeTime,WorkingSetSize,Priority,PageFileUsage,CreationDate | fl').then((stdout, error) => { if (!error) { let processSections = stdout.split(/\n\s*\n/); let procs = []; let procStats = []; let list_new = {}; let allcpuu = 0; let allcpus = 0; // let allcpuu = _processes_cpu.all_utime; // let allcpus = _processes_cpu.all_stime; for (let i = 0; i < processSections.length; i++) { if (processSections[i].trim() !== '') { let lines = processSections[i].trim().split('\r\n'); let pid = parseInt(util.getValue(lines, 'ProcessId', ':', true), 10); let parentPid = parseInt(util.getValue(lines, 'ParentProcessId', ':', true), 10); let statusValue = util.getValue(lines, 'ExecutionState', ':'); let name = util.getValue(lines, 'Caption', ':', true); let commandLine = util.getValue(lines, 'CommandLine', ':', true); let commandPath = util.getValue(lines, 'ExecutablePath', ':', true); let utime = parseInt(util.getValue(lines, 'UserModeTime', ':', true), 10); let stime = parseInt(util.getValue(lines, 'KernelModeTime', ':', true), 10); let memw = parseInt(util.getValue(lines, 'WorkingSetSize', ':', true), 10); allcpuu = allcpuu + utime; allcpus = allcpus + stime; // allcpuu += utime - (_processes_cpu.list[pid] ? _processes_cpu.list[pid].utime : 0); // allcpus += stime - (_processes_cpu.list[pid] ? _processes_cpu.list[pid].stime : 0); result.all++; if (!statusValue) { result.unknown++; } if (statusValue === '3') { result.running++; } if (statusValue === '4' || statusValue === '5') { result.blocked++; } procStats.push({ pid: pid, utime: utime, stime: stime, cpu: 0, cpuu: 0, cpus: 0, }); procs.push({ pid: pid, parentPid: parentPid, name: name, cpu: 0, cpuu: 0, cpus: 0, mem: memw / os.totalmem() * 100, priority: parseInt(util.getValue(lines, 'Priority', ':', true), 10), memVsz: parseInt(util.getValue(lines, 'PageFileUsage', ':', true), 10), memRss: Math.floor(parseInt(util.getValue(lines, 'WorkingSetSize', ':', true), 10) / 1024), nice: 0, started: parseTimeWin(util.getValue(lines, 'CreationDate', ':', true)), state: (!statusValue ? _winStatusValues[0] : _winStatusValues[statusValue]), tty: '', user: '', command: commandLine || name, path: commandPath, params: '' }); } } result.sleeping = result.all - result.running - result.blocked - result.unknown; result.list = procs; for (let i = 0; i < procStats.length; i++) { let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _processes_cpu); // store pcpu in outer array let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid); if (listPos >= 0) { result.list[listPos].cpu = resultProcess.cpuu + resultProcess.cpus; result.list[listPos].cpuu = resultProcess.cpuu; result.list[listPos].cpus = resultProcess.cpus; } // save new values list_new[resultProcess.pid] = { cpuu: resultProcess.cpuu, cpus: resultProcess.cpus, utime: resultProcess.utime, stime: resultProcess.stime }; } // store old values _processes_cpu.all = allcpuu + allcpus; _processes_cpu.all_utime = allcpuu; _processes_cpu.all_stime = allcpus; // _processes_cpu.list = list_new; _processes_cpu.list = Object.assign({}, list_new); _processes_cpu.ms = Date.now() - _processes_cpu.ms; // _processes_cpu.result = result; _processes_cpu.result = Object.assign({}, result); } if (callback) { callback(result); } resolve(result); }); } catch (e) { if (callback) { callback(result); } resolve(result); } } else { if (callback) { callback(result); } resolve(result); } } else { if (callback) { callback(_processes_cpu.result); } resolve(_processes_cpu.result); } }); }); } exports.processes = processes; // -------------------------- // PS - process load // get detailed information about a certain process // (PID, CPU-Usage %, Mem-Usage %) function processLoad(proc, callback) { // fallback - if only callback is given if (util.isFunction(proc) && !callback) { callback = proc; proc = ''; } return new Promise((resolve) => { process.nextTick(() => { proc = proc || ''; if (typeof proc !== 'string') { if (callback) { callback([]); } return resolve([]); } let processesString = ''; processesString.__proto__.toLowerCase = util.stringToLower; processesString.__proto__.replace = util.stringReplace; processesString.__proto__.trim = util.stringTrim; const s = util.sanitizeShellString(proc); for (let i = 0; i <= util.mathMin(s.length, 2000); i++) { if (!(s[i] === undefined)) { processesString = processesString + s[i]; } } processesString = processesString.trim().toLowerCase().replace(/, /g, '|').replace(/,+/g, '|'); if (processesString === '') { processesString = '*'; } if (util.isPrototypePolluted() && processesString !== '*') { processesString = '------'; } let processes = processesString.split('|'); let result = []; const procSanitized = util.isPrototypePolluted() ? '' : util.sanitizeShellString(proc); // from here new // let result = { // 'proc': procSanitized, // 'pid': null, // 'cpu': 0, // 'mem': 0 // }; if (procSanitized && processes.length && processes[0] !== '------') { if (_windows) { try { util.powerShell('Get-WmiObject Win32_Process | select ProcessId,Caption,UserModeTime,KernelModeTime,WorkingSetSize | fl').then((stdout, error) => { if (!error) { let processSections = stdout.split(/\n\s*\n/); let procStats = []; let list_new = {}; let allcpuu = 0; let allcpus = 0; // let allcpuu = _process_cpu.all_utime; // let allcpus = _process_cpu.all_stime; // go through all processes for (let i = 0; i < processSections.length; i++) { if (processSections[i].trim() !== '') { let lines = processSections[i].trim().split('\r\n'); let pid = parseInt(util.getValue(lines, 'ProcessId', ':', true), 10); let name = util.getValue(lines, 'Caption', ':', true); let utime = parseInt(util.getValue(lines, 'UserModeTime', ':', true), 10); let stime = parseInt(util.getValue(lines, 'KernelModeTime', ':', true), 10); let mem = parseInt(util.getValue(lines, 'WorkingSetSize', ':', true), 10); allcpuu = allcpuu + utime; allcpus = allcpus + stime; // allcpuu += utime - (_process_cpu.list[pid] ? _process_cpu.list[pid].utime : 0); // allcpus += stime - (_process_cpu.list[pid] ? _process_cpu.list[pid].stime : 0); procStats.push({ pid: pid, name, utime: utime, stime: stime, cpu: 0, cpuu: 0, cpus: 0, mem }); let pname = ''; let inList = false; processes.forEach(function (proc) { // console.log(proc) // console.log(item) // inList = inList || item.name.toLowerCase() === proc.toLowerCase(); if (name.toLowerCase().indexOf(proc.toLowerCase()) >= 0 && !inList) { inList = true; pname = proc; } }); if (processesString === '*' || inList) { let processFound = false; result.forEach(function (item) { if (item.proc.toLowerCase() === pname.toLowerCase()) { item.pids.push(pid); item.mem += mem / os.totalmem() * 100; processFound = true; } }); if (!processFound) { result.push({ proc: pname, pid: pid, pids: [pid], cpu: 0, mem: mem / os.totalmem() * 100 }); } } } } // add missing processes if (processesString !== '*') { let processesMissing = processes.filter(function (name) { // return procStats.filter(function(item) { return item.name.toLowerCase() === name }).length === 0; return procStats.filter(function (item) { return item.name.toLowerCase().indexOf(name) >= 0; }).length === 0; }); processesMissing.forEach(function (procName) { result.push({ proc: procName, pid: null, pids: [], cpu: 0, mem: 0 }); }); } // calculate proc stats for each proc for (let i = 0; i < procStats.length; i++) { let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _process_cpu); let listPos = -1; for (let j = 0; j < result.length; j++) { if (result[j].pid === resultProcess.pid || result[j].pids.indexOf(resultProcess.pid) >= 0) { listPos = j; } } if (listPos >= 0) { result[listPos].cpu += resultProcess.cpuu + resultProcess.cpus; } // save new values list_new[resultProcess.pid] = { cpuu: resultProcess.cpuu, cpus: resultProcess.cpus, utime: resultProcess.utime, stime: resultProcess.stime }; } // store old values _process_cpu.all = allcpuu + allcpus; _process_cpu.all_utime = allcpuu; _process_cpu.all_stime = allcpus; // _process_cpu.list = list_new; _process_cpu.list = Object.assign({}, list_new); _process_cpu.ms = Date.now() - _process_cpu.ms; _process_cpu.result = JSON.parse(JSON.stringify(result)); if (callback) { callback(result); } resolve(result); } }); } catch (e) { if (callback) { callback(result); } resolve(result); } } if (_darwin || _linux || _freebsd || _openbsd || _netbsd) { const params = ['-axo', 'pid,pcpu,pmem,comm']; util.execSafe('ps', params).then((stdout) => { if (stdout) { let procStats = []; let lines = stdout.toString().split('\n').filter(function (line) { if (processesString === '*') { return true; } if (line.toLowerCase().indexOf('grep') !== -1) { return false; } // remove this?? let found = false; processes.forEach(function (item) { found = found || (line.toLowerCase().indexOf(item.toLowerCase()) >= 0); }); return found; }); lines.forEach(function (line) { let data = line.trim().replace(/ +/g, ' ').split(' '); if (data.length > 3) { procStats.push({ name: data[3].substring(data[3].lastIndexOf('/') + 1), pid: parseInt(data[0]) || 0, cpu: parseFloat(data[1].replace(',', '.')), mem: parseFloat(data[2].replace(',', '.')) }); } }); procStats.forEach(function (item) { let listPos = -1; let inList = false; let name = ''; for (let j = 0; j < result.length; j++) { // if (result[j].proc.toLowerCase() === item.name.toLowerCase()) { // if (result[j].proc.toLowerCase().indexOf(item.name.toLowerCase()) >= 0) { if (item.name.toLowerCase().indexOf(result[j].proc.toLowerCase()) >= 0) { listPos = j; } } // console.log(listPos); processes.forEach(function (proc) { // console.log(proc) // console.log(item) // inList = inList || item.name.toLowerCase() === proc.toLowerCase(); if (item.name.toLowerCase().indexOf(proc.toLowerCase()) >= 0 && !inList) { inList = true; name = proc; } }); // console.log(item); // console.log(listPos); if ((processesString === '*') || inList) { if (listPos < 0) { result.push({ proc: name, pid: item.pid, pids: [item.pid], cpu: item.cpu, mem: item.mem }); } else { result[listPos].pids.push(item.pid); result[listPos].cpu += item.cpu; result[listPos].mem += item.mem; } } }); if (processesString !== '*') { // add missing processes let processesMissing = processes.filter(function (name) { return procStats.filter(function (item) { return item.name.toLowerCase().indexOf(name) >= 0; }).length === 0; }); processesMissing.forEach(function (procName) { result.push({ proc: procName, pid: null, pids: [], cpu: 0, mem: 0 }); }); } if (_linux) { // calc process_cpu - ps is not accurate in linux! result.forEach(function (item) { item.cpu = 0; }); let cmd = 'cat /proc/stat | grep "cpu "'; for (let i in result) { for (let j in result[i].pids) { cmd += (';cat /proc/' + result[i].pids[j] + '/stat'); } } exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { let curr_processes = stdout.toString().split('\n'); // first line (all - /proc/stat) let all = parseProcStat(curr_processes.shift()); // process let list_new = {}; let resultProcess = {}; for (let i = 0; i < curr_processes.length; i++) { resultProcess = calcProcStatLinux(curr_processes[i], all, _process_cpu); if (resultProcess.pid) { // find result item let resultItemId = -1; for (let i in result) { if (result[i].pids.indexOf(resultProcess.pid) >= 0) { resultItemId = i; } } // store pcpu in outer result if (resultItemId >= 0) { result[resultItemId].cpu += resultProcess.cpuu + resultProcess.cpus; } // save new values list_new[resultProcess.pid] = { cpuu: resultProcess.cpuu, cpus: resultProcess.cpus, utime: resultProcess.utime, stime: resultProcess.stime, cutime: resultProcess.cutime, cstime: resultProcess.cstime }; } } result.forEach(function (item) { item.cpu = Math.round(item.cpu * 100) / 100; }); _process_cpu.all = all; // _process_cpu.list = list_new; _process_cpu.list = Object.assign({}, list_new); _process_cpu.ms = Date.now() - _process_cpu.ms; // _process_cpu.result = result; _process_cpu.result = Object.assign({}, result); if (callback) { callback(result); } resolve(result); }); } else { if (callback) { callback(result); } resolve(result); } } else { if (callback) { callback(result); } resolve(result); } }); } } }); }); } exports.processLoad = processLoad;