[6a3a178] | 1 | 'use strict';
|
---|
| 2 |
|
---|
| 3 | var childProcess = require('child_process');
|
---|
| 4 | var spawn = childProcess.spawn;
|
---|
| 5 | var exec = childProcess.exec;
|
---|
| 6 |
|
---|
| 7 | module.exports = function (pid, signal, callback) {
|
---|
| 8 | if (typeof signal === 'function' && callback === undefined) {
|
---|
| 9 | callback = signal;
|
---|
| 10 | signal = undefined;
|
---|
| 11 | }
|
---|
| 12 |
|
---|
| 13 | pid = parseInt(pid);
|
---|
| 14 | if (Number.isNaN(pid)) {
|
---|
| 15 | if (callback) {
|
---|
| 16 | return callback(new Error("pid must be a number"));
|
---|
| 17 | } else {
|
---|
| 18 | throw new Error("pid must be a number");
|
---|
| 19 | }
|
---|
| 20 | }
|
---|
| 21 |
|
---|
| 22 | var tree = {};
|
---|
| 23 | var pidsToProcess = {};
|
---|
| 24 | tree[pid] = [];
|
---|
| 25 | pidsToProcess[pid] = 1;
|
---|
| 26 |
|
---|
| 27 | switch (process.platform) {
|
---|
| 28 | case 'win32':
|
---|
| 29 | exec('taskkill /pid ' + pid + ' /T /F', callback);
|
---|
| 30 | break;
|
---|
| 31 | case 'darwin':
|
---|
| 32 | buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
|
---|
| 33 | return spawn('pgrep', ['-P', parentPid]);
|
---|
| 34 | }, function () {
|
---|
| 35 | killAll(tree, signal, callback);
|
---|
| 36 | });
|
---|
| 37 | break;
|
---|
| 38 | // case 'sunos':
|
---|
| 39 | // buildProcessTreeSunOS(pid, tree, pidsToProcess, function () {
|
---|
| 40 | // killAll(tree, signal, callback);
|
---|
| 41 | // });
|
---|
| 42 | // break;
|
---|
| 43 | default: // Linux
|
---|
| 44 | buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
|
---|
| 45 | return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
|
---|
| 46 | }, function () {
|
---|
| 47 | killAll(tree, signal, callback);
|
---|
| 48 | });
|
---|
| 49 | break;
|
---|
| 50 | }
|
---|
| 51 | };
|
---|
| 52 |
|
---|
| 53 | function killAll (tree, signal, callback) {
|
---|
| 54 | var killed = {};
|
---|
| 55 | try {
|
---|
| 56 | Object.keys(tree).forEach(function (pid) {
|
---|
| 57 | tree[pid].forEach(function (pidpid) {
|
---|
| 58 | if (!killed[pidpid]) {
|
---|
| 59 | killPid(pidpid, signal);
|
---|
| 60 | killed[pidpid] = 1;
|
---|
| 61 | }
|
---|
| 62 | });
|
---|
| 63 | if (!killed[pid]) {
|
---|
| 64 | killPid(pid, signal);
|
---|
| 65 | killed[pid] = 1;
|
---|
| 66 | }
|
---|
| 67 | });
|
---|
| 68 | } catch (err) {
|
---|
| 69 | if (callback) {
|
---|
| 70 | return callback(err);
|
---|
| 71 | } else {
|
---|
| 72 | throw err;
|
---|
| 73 | }
|
---|
| 74 | }
|
---|
| 75 | if (callback) {
|
---|
| 76 | return callback();
|
---|
| 77 | }
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | function killPid(pid, signal) {
|
---|
| 81 | try {
|
---|
| 82 | process.kill(parseInt(pid, 10), signal);
|
---|
| 83 | }
|
---|
| 84 | catch (err) {
|
---|
| 85 | if (err.code !== 'ESRCH') throw err;
|
---|
| 86 | }
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
|
---|
| 90 | var ps = spawnChildProcessesList(parentPid);
|
---|
| 91 | var allData = '';
|
---|
| 92 | ps.stdout.on('data', function (data) {
|
---|
| 93 | var data = data.toString('ascii');
|
---|
| 94 | allData += data;
|
---|
| 95 | });
|
---|
| 96 |
|
---|
| 97 | var onClose = function (code) {
|
---|
| 98 | delete pidsToProcess[parentPid];
|
---|
| 99 |
|
---|
| 100 | if (code != 0) {
|
---|
| 101 | // no more parent processes
|
---|
| 102 | if (Object.keys(pidsToProcess).length == 0) {
|
---|
| 103 | cb();
|
---|
| 104 | }
|
---|
| 105 | return;
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | allData.match(/\d+/g).forEach(function (pid) {
|
---|
| 109 | pid = parseInt(pid, 10);
|
---|
| 110 | tree[parentPid].push(pid);
|
---|
| 111 | tree[pid] = [];
|
---|
| 112 | pidsToProcess[pid] = 1;
|
---|
| 113 | buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
|
---|
| 114 | });
|
---|
| 115 | };
|
---|
| 116 |
|
---|
| 117 | ps.on('close', onClose);
|
---|
| 118 | }
|
---|