2023-10-31 13:05:45 +00:00
|
|
|
import { promisify } from 'util'
|
|
|
|
import { spawn, exec } from 'child_process'
|
|
|
|
|
|
|
|
const execPromise = promisify(exec)
|
|
|
|
|
|
|
|
export default function kill(pid, signal) {
|
2024-03-01 09:39:59 +00:00
|
|
|
let pids = new Set([pid])
|
2023-10-31 13:05:45 +00:00
|
|
|
let getSpawn = null
|
2024-03-01 09:39:59 +00:00
|
|
|
let getPids = null
|
2023-10-31 13:05:45 +00:00
|
|
|
|
|
|
|
switch (process.platform) {
|
|
|
|
case 'win32':
|
2024-03-01 09:39:59 +00:00
|
|
|
return execPromise('taskkill /pid ' + pid + ' /T /F').then(() => pids)
|
2023-10-31 13:05:45 +00:00
|
|
|
case 'darwin':
|
|
|
|
getSpawn = function(parentPid) {
|
|
|
|
return spawn('pgrep', ['-P', parentPid])
|
|
|
|
}
|
2024-03-01 09:39:59 +00:00
|
|
|
getPids = function(data) {
|
|
|
|
return data.match(/\d+/g).map(Number)
|
|
|
|
}
|
2023-10-31 13:05:45 +00:00
|
|
|
break
|
|
|
|
default:
|
|
|
|
getSpawn = function (parentPid) {
|
2024-03-01 09:39:59 +00:00
|
|
|
return exec('ps -opid="" -oppid="" | grep ' + parentPid)
|
|
|
|
}
|
|
|
|
getPids = function(data, parentPid) {
|
|
|
|
let output = data.trim().split('\n')
|
|
|
|
return output.map(line => {
|
|
|
|
let [child, parent] = line.trim().split(/ +/)
|
|
|
|
|
|
|
|
if (Number(parent) === parentPid) {
|
|
|
|
return Number(child)
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}).filter(x => x)
|
2023-10-31 13:05:45 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2024-03-01 09:39:59 +00:00
|
|
|
return buildTree(pids, getSpawn, getPids, pid)
|
2023-10-31 13:05:45 +00:00
|
|
|
.then(function() {
|
|
|
|
for (let pid of pids) {
|
|
|
|
try {
|
|
|
|
process.kill(pid, signal)
|
|
|
|
} catch (err) {
|
|
|
|
if (err.code !== 'ESRCH') throw err;
|
|
|
|
}
|
|
|
|
}
|
2024-03-01 09:39:59 +00:00
|
|
|
return pids
|
2023-10-31 13:05:45 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-03-01 09:39:59 +00:00
|
|
|
function buildTree(allPids, spawnGetChildren, spawnGetPids, parentPid) {
|
2023-10-31 13:25:08 +00:00
|
|
|
allPids.add(parentPid)
|
2023-10-31 13:05:45 +00:00
|
|
|
|
|
|
|
let ps = spawnGetChildren(parentPid)
|
|
|
|
let data = ''
|
2024-03-01 09:39:59 +00:00
|
|
|
let err = ''
|
2023-10-31 13:05:45 +00:00
|
|
|
ps.stdout.on('data', function(buf) {
|
|
|
|
data += buf.toString('ascii')
|
|
|
|
})
|
2024-03-01 09:39:59 +00:00
|
|
|
ps.stderr.on('data', function(buf) {
|
|
|
|
err += buf.toString('ascii')
|
|
|
|
})
|
2023-10-31 13:05:45 +00:00
|
|
|
|
2024-03-01 09:39:59 +00:00
|
|
|
return new Promise(function(res, rej) {
|
2023-10-31 13:05:45 +00:00
|
|
|
ps.on('close', function(code) {
|
2024-03-01 09:39:59 +00:00
|
|
|
// Check if ps errored out
|
|
|
|
if (code !== 0 && err.trim()) {
|
|
|
|
return rej(new Error('Error running ps to kill processes:\n\t' + err))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we otherwise got an error code (usually means empty results)
|
|
|
|
if (code !== 0 || !data.trim()) return res()
|
|
|
|
|
|
|
|
let pids = spawnGetPids(data, parentPid)
|
2023-10-31 13:05:45 +00:00
|
|
|
|
|
|
|
res(Promise.all(
|
2024-03-01 09:39:59 +00:00
|
|
|
pids.filter(pid => pid && !allPids.has(pid))
|
|
|
|
.map(buildTree.bind(this, allPids, spawnGetChildren, spawnGetPids))
|
2023-10-31 13:05:45 +00:00
|
|
|
))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|