diff --git a/lib/TreeKill.js b/lib/TreeKill.js index f3066d0e..6e429962 100644 --- a/lib/TreeKill.js +++ b/lib/TreeKill.js @@ -1,54 +1,31 @@ -/**! - * treekill - index.js - * - * Copyright(c) fengmk2 and other contributors. - * MIT Licensed - * - * Authors: - * fengmk2 (http://fengmk2.github.com) - * - * Github: - * https://github.com/node-modules/treekill - */ - /** - * Module dependencies. + * + * Reference: https://github.com/pkrumins/node-tree-kill + * Author : pkrumins + * + * Update : PM2 team + * */ -var childProcess = require('child_process'); -var spawn = childProcess.spawn; -var exec = childProcess.exec; -var isWindows = process.platform === 'win32'; -var isDarwin = process.platform === 'darwin'; +var exec = require('child_process').exec, + isWin = process.platform === 'win32', + downgradePs = false; -module.exports = treekill; - -function treekill(pid, signal, callback) { - if (typeof signal === 'function') { - callback = signal; - signal = null; - } - - if (isWindows) { +module.exports = function(pid, signal){ + if (isWin) { exec('taskkill /pid ' + pid + ' /T /F'); } else { - var tree = {}; - tree[pid] = []; - var pidsToProcess = {}; - pidsToProcess[pid] = 1; - buildProcessTree(pid, tree, pidsToProcess, function () { + var tree = {}, pidsToProcess = {}; + buildProcessTree(pid, tree, pidsToProcess, function(){ killAll(tree, signal); - if (typeof callback === 'function') { - callback(); - } }); } } -function killAll(tree, signal) { +function killAll(tree, signal){ var killed = {}; - Object.keys(tree).forEach(function (pid) { - tree[pid].forEach(function (pidpid) { + Object.keys(tree).forEach(function(pid){ + tree[pid].forEach(function(pidpid){ if (!killed[pidpid]) { killPid(pidpid, signal); killed[pidpid] = 1; @@ -61,49 +38,73 @@ function killAll(tree, signal) { }); } -function killPid(pid, signal) { +function killPid(pid, signal){ try { - process.kill(parseInt(pid), signal); - } catch (err) { - if (err.code !== 'ESRCH') { + process.kill(pid, signal); + } + catch (err) { + if (err.code == 'EINVAL'){ + throw new Error('The value of the sig argument is an invalid or unsupported signal number.'); + } + if(err.code == 'EPERM'){ + throw new Error('The process does not have permission to send the signal to any receiving process.'); + } + if (err.code !== 'ESRCH'){ throw err; } } } -function buildProcessTree(ppid, tree, pidsToProcess, cb) { - var cmd = 'ps -e -o pid,ppid'; - ppid = String(ppid); - exec(cmd, function (err, stdout, stderr) { - if (err) { - console.log(stderr); - throw err; - } - var lines = stdout.toString().split('\n'); - lines = lines.map(function (line) { - return line.trim().split(/ +/).map(function (item) { - return item.trim(); - }); - }); +function buildProcessTree(ppid, tree, pidsToProcess, cb){ + pidsToProcess[ppid] = 1; + tree[ppid] = []; + + function isFinish(){ delete pidsToProcess[ppid]; - - var pids = []; - for (var i = 0; i < lines.length; i++) { - var item = lines[i]; - if (item[1] === ppid) { - pids.push(parseInt(item[0])); - } - } - - if (pids.length === 0 && Object.keys(pidsToProcess).length === 0) { + if(Object.keys(pidsToProcess).length == 0){ return cb(); } + } - pids.forEach(function (pid) { - tree[ppid].push(pid); - tree[pid] = []; - pidsToProcess[pid] = 1; - buildProcessTree(pid, tree, pidsToProcess, cb); + var args = downgradePs ? '-eo pid,ppid | grep -w ' : '-o pid --no-headers --ppid '; + var ps = exec('ps ' + args + ppid, function(err, stdout, stderr){ + if (err) { + // illegal option --, try to use basic `ps` instead of it. + if (/illegal/.test(err.message) && !downgradePs) { + downgradePs = true; + return buildProcessTree(ppid, tree, pidsToProcess, cb); + } + + // Avoid pipe close error - dynamic self-closing process. + if(/Command failed/.test(err.message)) { + return isFinish(); + } + throw err; + } + + var pids = stdout.split('\n'); + + // remove parentPid if necessary. + downgradePs && pids.shift(); + + pids = pids.filter(function(pid){ + return !!pid; + }).map(function(pid){ + pid = pid.trim(); + return parseInt(downgradePs ? pid.slice(0, pid.search(/\s/)) : pid, 10); }); + + if(pids.length > 0){ + tree[ppid] = tree[ppid].concat(pids); + pids.forEach(function(pid){ + if(!tree[pid]) { + buildProcessTree(pid, tree, pidsToProcess, cb); + }else{ + delete pidsToProcess[pid]; + } + }); + } + + isFinish(); }); }