index.js 3.1 KB

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