From dc1d6e5035c19860e9ba34f6fbc4f2c60b39a737 Mon Sep 17 00:00:00 2001 From: Sebastian Hildebrandt Date: Fri, 1 Jun 2018 13:41:06 +0200 Subject: [PATCH] processes() added parent process PID --- CHANGELOG.md | 1 + README.md | 1 + lib/network.js | 31 ++++++++-------- lib/processes.js | 92 ++++++++++++++++++++++++++---------------------- 4 files changed, 67 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65938e4..b448e66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,7 @@ Other changes | Version | Date | Comment | | -------------- | -------------- | -------- | +| 3.42.0 | 2018-06-01 | `processes()` added parent process PID | | 3.41.4 | 2018-05-28 | windows exec WMIC in try catch | | 3.41.3 | 2018-05-13 | improved SunOS support `getStaticData()`, `getDynamicData()` | | 3.41.2 | 2018-05-13 | bugfix `system()` and `flags()` Raspberry Pi | diff --git a/README.md b/README.md index 7be3897..46c66f6 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ I also created a nice little command line tool called [mmon][mmon-github-url] ( | | unknown | | | | X | | # of all processes unknown status | | | list[] | X | X | X | X | X | list of all processes incl. details | | | ...[0].pid | X | X | X | X | X | process PID | +| | ...[0].parentPid | X | X | X | X | X | parent process PID | | | ...[0].name | X | X | X | X | X | process name | | | ...[0].pcpu | X | X | X | X | X | process % CPU usage | | | ...[0].pcpuu | X | X | | X | | process % CPU usage (user) | diff --git a/lib/network.js b/lib/network.js index 59e76a5..13ff987 100644 --- a/lib/network.js +++ b/lib/network.js @@ -28,7 +28,8 @@ const _openbsd = (_platform === 'openbsd'); const _sunos = (_platform === 'sunos'); const opts = { - windowsHide: true + windowsHide: true, + maxBuffer: 1024 * 2000 }; let _network = {}; @@ -371,7 +372,7 @@ function networkStats(iface, callback) { if (!error) { const nsections = stdout.split(/\n\s*\n/); nics = parseLinesWindowsNics(nsections); - + // Performance Data cmd = util.getWmic() + ' path Win32_PerfRawData_Tcpip_NetworkInterface Get name,BytesReceivedPersec,BytesSentPersec,BytesTotalPersec /value'; exec(cmd, opts, function (error, stdout) { @@ -379,7 +380,7 @@ function networkStats(iface, callback) { const psections = stdout.split(/\n\s*\n/); perfData = parseLinesWindowsPerfData(psections); } - + // Network Interfaces networkInterfaces().then(interfaces => { // get mac from 'interfaces' by interfacename @@ -389,7 +390,7 @@ function networkStats(iface, callback) { mac = detail.mac; } }); - + // get name from 'nics' (by macadress) let name = ''; nics.forEach(detail => { @@ -398,7 +399,7 @@ function networkStats(iface, callback) { operstate = (detail.netEnabled ? 'up' : 'down'); } }); - + // get bytes sent, received from perfData by name rx = 0; tx = 0; @@ -408,7 +409,7 @@ function networkStats(iface, callback) { tx = detail.tx; } }); - + if (rx && tx) { result = calcNetworkSpeed(iface, parseInt(rx), parseInt(tx), operstate); } @@ -417,10 +418,10 @@ function networkStats(iface, callback) { }); }); } - }); + }); } catch (e) { if (callback) { callback(result); } - resolve(result); + resolve(result); } } } else { @@ -450,7 +451,7 @@ function networkConnections(callback) { if (_linux || _freebsd || _openbsd) { let cmd = 'netstat -tuna | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN\\|VERBUNDEN"'; if (_freebsd || _openbsd) cmd = 'netstat -na | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN\\|VERBUNDEN"'; - exec(cmd, function (error, stdout) { + exec(cmd, { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); lines.forEach(function (line) { @@ -492,7 +493,7 @@ function networkConnections(callback) { resolve(result); } else { cmd = 'ss -tuna | grep "ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING"'; - exec(cmd, function (error, stdout) { + exec(cmd, { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); @@ -541,7 +542,7 @@ function networkConnections(callback) { } if (_darwin) { let cmd = 'netstat -nat | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"'; - exec(cmd, function (error, stdout) { + exec(cmd, { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); @@ -590,9 +591,9 @@ function networkConnections(callback) { try { exec(cmd, opts, function (error, stdout) { if (!error) { - + let lines = stdout.toString().split('\r\n'); - + lines.forEach(function (line) { line = line.trim().replace(/ +/g, ' ').split(' '); if (line.length >= 4) { @@ -618,7 +619,7 @@ function networkConnections(callback) { if (connstate === 'SCHLIESSEN_WARTEN') connstate = 'CLOSE_WAIT'; if (connstate === 'WARTEND') connstate = 'TIME_WAIT'; if (connstate === 'SYN_GESENDET') connstate = 'SYN_SENT'; - + if (connstate === 'LISTENING') connstate = 'LISTEN'; if (connstate === 'SYN_RECEIVED') connstate = 'SYN_RECV'; if (connstate === 'FIN_WAIT_1') connstate = 'FIN_WAIT1'; @@ -643,7 +644,7 @@ function networkConnections(callback) { }); } catch (e) { if (callback) { callback(result); } - resolve(result); + resolve(result); } } }); diff --git a/lib/processes.js b/lib/processes.js index b9c0c66..82589a7 100644 --- a/lib/processes.js +++ b/lib/processes.js @@ -82,7 +82,7 @@ function services(srv, callback) { if (_linux || _freebsd || _openbsd || _darwin) { let comm = (_darwin) ? 'ps -caxo pcpu,pmem,comm' : 'ps -axo pcpu,pmem,comm'; if (srv !== '' && srvs.length > 0) { - exec(comm + ' | grep -v grep | egrep "' + srv + '"', function (error, stdout) { + exec(comm + ' | grep -v grep | egrep "' + srv + '"', { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n'); srvs.forEach(function (srv) { @@ -103,7 +103,7 @@ function services(srv, callback) { if (callback) { callback(data); } resolve(data); } else { - exec('ps -o comm | grep -v grep | egrep "' + srv + '"', function (error, stdout) { + exec('ps -o comm | grep -v grep | egrep "' + srv + '"', { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n'); srvs.forEach(function (srv) { @@ -171,7 +171,7 @@ function services(srv, callback) { 'pmem': 0 }); }); - + if (callback) { callback(data); } resolve(data); } else { @@ -186,10 +186,10 @@ function services(srv, callback) { if (callback) { callback(data); } resolve(data); } - }); + }); } catch (e) { if (callback) { callback(data); } - resolve(data); + resolve(data); } } } else { @@ -279,32 +279,35 @@ function processes(callback) { checkColumn(0); let pid = parseInt(line.substring(parsedhead[0].from + offset, parsedhead[0].to + offset2)); checkColumn(1); - let pcpu = parseFloat(line.substring(parsedhead[1].from + offset, parsedhead[1].to + offset2).replace(/,/g, '.')); + let ppid = parseInt(line.substring(parsedhead[1].from + offset, parsedhead[1].to + offset2)); checkColumn(2); - let pmem = parseFloat(line.substring(parsedhead[2].from + offset, parsedhead[2].to + offset2).replace(/,/g, '.')); + let pcpu = parseFloat(line.substring(parsedhead[2].from + offset, parsedhead[2].to + offset2).replace(/,/g, '.')); checkColumn(3); - let priority = parseInt(line.substring(parsedhead[3].from + offset, parsedhead[3].to + offset2)); + let pmem = parseFloat(line.substring(parsedhead[3].from + offset, parsedhead[3].to + offset2).replace(/,/g, '.')); checkColumn(4); - let vsz = parseInt(line.substring(parsedhead[4].from + offset, parsedhead[4].to + offset2)); + let priority = parseInt(line.substring(parsedhead[4].from + offset, parsedhead[4].to + offset2)); checkColumn(5); - let rss = parseInt(line.substring(parsedhead[5].from + offset, parsedhead[5].to + offset2)); + let vsz = parseInt(line.substring(parsedhead[5].from + offset, parsedhead[5].to + offset2)); checkColumn(6); - let nice = parseInt(line.substring(parsedhead[6].from + offset, parsedhead[6].to + offset2)) || 0; + let rss = parseInt(line.substring(parsedhead[6].from + offset, parsedhead[6].to + offset2)); checkColumn(7); - let started = line.substring(parsedhead[7].from + offset, parsedhead[7].to + offset2).trim(); + let nice = parseInt(line.substring(parsedhead[7].from + offset, parsedhead[7].to + offset2)) || 0; checkColumn(8); - let state = line.substring(parsedhead[8].from + offset, parsedhead[8].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'))))))); + let started = line.substring(parsedhead[8].from + offset, parsedhead[8].to + offset2).trim(); checkColumn(9); - let tty = line.substring(parsedhead[9].from + offset, parsedhead[9].to + offset2).trim(); - if (tty === '?' || tty === '??') tty = ''; + 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 user = line.substring(parsedhead[10].from + offset, parsedhead[10].to + offset2).trim(); + let tty = line.substring(parsedhead[10].from + offset, parsedhead[10].to + offset2).trim(); + if (tty === '?' || tty === '??') tty = ''; checkColumn(11); - let command = line.substring(parsedhead[11].from + offset, parsedhead[11].to + offset2).trim().replace(/\[/g, '').replace(/]/g, ''); + let user = line.substring(parsedhead[11].from + offset, parsedhead[11].to + offset2).trim(); + checkColumn(12); + let command = line.substring(parsedhead[12].from + offset, parsedhead[12].to + offset2).trim().replace(/\[/g, '').replace(/]/g, ''); return ({ pid: pid, + parentPid: ppid, name: _linux ? getName(command) : command, pcpu: pcpu, pcpuu: 0, @@ -354,26 +357,27 @@ function processes(callback) { if (line.trim() !== '') { line = line.trim().replace(/ +/g, ' ').replace(/,+/g, '.'); const parts = line.split(' '); - const command = parts.slice(8).join(' '); - const pmem = parseFloat((1.0 * parseInt(parts[2]) * 1024 / os.totalmem()).toFixed(1)); - const elapsed_parts = parts[4].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), pcpu: 0, pcpuu: 0, pcpus: 0, pmem: pmem, priority: 0, - mem_vsz: parseInt(parts[1]), - mem_rss: parseInt(parts[2]), - nice: parseInt(parts[3]), + mem_vsz: parseInt(parts[2]), + mem_rss: parseInt(parts[3]), + nice: parseInt(parts[4]), started: started, - state: (parts[5] === 'R' ? 'running' : (parts[5] === 'S' ? 'sleeping' : (parts[5] === 'T' ? 'stopped' : (parts[5] === 'W' ? 'paging' : (parts[5] === 'X' ? 'dead' : (parts[5] === 'Z' ? 'zombie' : ((parts[5] === 'D' || parts[5] === 'U') ? 'blocked' : 'unknown'))))))), - tty: parts[6], - user: parts[7], + 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 }); } @@ -485,11 +489,11 @@ function processes(callback) { if ((_process_cpu.ms && Date.now() - _process_cpu.ms >= 500) || _process_cpu.ms === 0) { if (_linux || _freebsd || _openbsd || _darwin || _sunos) { - if (_linux) cmd = 'ps -axo pid:10,pcpu:6,pmem:6,pri:5,vsz:10,rss:10,ni:5,start:20,state:20,tty:20,user:20,command'; - if (_freebsd || _openbsd) cmd = 'ps -axo pid,pcpu,pmem,pri,vsz,rss,ni,start,state,tty,user,command'; - if (_darwin) cmd = 'ps -acxo pid,pcpu,pmem,pri,vsz,rss,nice,start,state,tty,user,command -r'; - if (_sunos) cmd = 'ps -Ao pid,pcpu,pmem,pri,vsz,rss,nice,stime,s,tty,user,comm'; - exec(cmd, function (error, stdout) { + if (_linux) cmd = 'ps -axo pid:10,ppid:10,pcpu:6,pmem:6,pri:5,vsz:10,rss:10,ni:5,start:20,state:20,tty:20,user:20,command'; + if (_freebsd || _openbsd) cmd = 'ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,ni,start,state,tty,user,command'; + if (_darwin) cmd = 'ps -acxo pid,ppid,pcpu,pmem,pri,vsz,rss,nice,start,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 * 2000 }, function (error, stdout) { if (!error) { result.list = parseProcesses(stdout.toString().split('\n')); result.all = result.list.length; @@ -509,7 +513,7 @@ function processes(callback) { for (let i = 0; i < result.list.length; i++) { cmd += (';cat /proc/' + result.list[i].pid + '/stat'); } - exec(cmd, function (error, stdout) { + exec(cmd, { maxBuffer: 1024 * 2000 }, function (error, stdout) { let curr_processes = stdout.toString().split('\n'); // first line (all - /proc/stat) @@ -556,11 +560,11 @@ function processes(callback) { resolve(result); } } else { - cmd = 'ps -o pid,vsz,rss,nice,etime,stat,tty,user,comm'; + cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,stat,tty,user,comm'; if (_sunos) { - cmd = 'ps -o pid,vsz,rss,nice,etime,s,tty,user,comm'; + cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,s,tty,user,comm'; } - exec(cmd, function (error, stdout) { + exec(cmd, { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); lines.shift(); @@ -588,7 +592,7 @@ function processes(callback) { } if (_windows) { try { - exec(util.getWmic() + ' process get /value', { maxBuffer: 1024 * 1000, windowsHide: true }, function (error, stdout) { + exec(util.getWmic() + ' process get /value', { maxBuffer: 1024 * 2000, windowsHide: true }, function (error, stdout) { if (!error) { let processSections = stdout.split(/\n\s*\n/); let procs = []; @@ -600,6 +604,7 @@ function processes(callback) { 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); @@ -612,7 +617,7 @@ function processes(callback) { if (!statusValue) { result.unknown++; } if (statusValue === '3') { result.running++; } if (statusValue === '4' || statusValue === '5') { result.blocked++; } - + procStats.push({ pid: pid, utime: utime, @@ -623,6 +628,7 @@ function processes(callback) { }); procs.push({ pid: pid, + parentPid: parentPid, name: name, pcpu: 0, pcpuu: 0, @@ -644,7 +650,7 @@ function processes(callback) { result.list = procs; for (let i = 0; i < procStats.length; i++) { let resultProcess = calcProcPidStat(procStats[i], allcpuu + allcpus); - + // store pcpu in outer array let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid); if (listPos >= 0) { @@ -652,7 +658,7 @@ function processes(callback) { result.list[listPos].pcpuu = resultProcess.pcpuu; result.list[listPos].pcpus = resultProcess.pcpus; } - + // save new values list_new[resultProcess.pid] = { pcpuu: resultProcess.pcpuu, @@ -671,10 +677,10 @@ function processes(callback) { callback(result); } resolve(result); - }); + }); } catch (e) { if (callback) { callback(result); } - resolve(result); + resolve(result); } } } else { @@ -716,7 +722,7 @@ function processLoad(proc, callback) { }; if (proc) { - exec('ps -axo pid,pcpu,pmem,comm | grep ' + proc + ' | grep -v grep', function (error, stdout) { + exec('ps -axo pid,pcpu,pmem,comm | grep ' + proc + ' | grep -v grep', { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n');