238 lines
6.3 KiB
JavaScript
238 lines
6.3 KiB
JavaScript
/*
|
|
* @Author: zoujie.wzj
|
|
* @Date: 2016-01-23 18:25:37
|
|
* @Last Modified by: Sahel LUCAS--SAOUDI
|
|
* @Last Modified on: 2021-11-12
|
|
*/
|
|
|
|
'use strict'
|
|
|
|
const path = require('path')
|
|
const utils = require('./utils')
|
|
|
|
function matchName (text, name) {
|
|
if (!name) {
|
|
return true
|
|
}
|
|
// make sure text.match is valid, fix #30
|
|
if (text && text.match) {
|
|
return text.match(name)
|
|
}
|
|
return false
|
|
}
|
|
|
|
function fetchBin (cmd) {
|
|
const pieces = cmd.split(path.sep)
|
|
const last = pieces[pieces.length - 1]
|
|
if (last) {
|
|
pieces[pieces.length - 1] = last.split(' ')[0]
|
|
}
|
|
const fixed = []
|
|
for (const part of pieces) {
|
|
const optIdx = part.indexOf(' -')
|
|
if (optIdx >= 0) {
|
|
// case: /aaa/bbb/ccc -c
|
|
fixed.push(part.substring(0, optIdx).trim())
|
|
break
|
|
} else if (part.endsWith(' ')) {
|
|
// case: node /aaa/bbb/ccc.js
|
|
fixed.push(part.trim())
|
|
break
|
|
}
|
|
fixed.push(part)
|
|
}
|
|
return fixed.join(path.sep)
|
|
}
|
|
|
|
function fetchName (fullpath) {
|
|
if (process.platform === 'darwin') {
|
|
const idx = fullpath.indexOf('.app/')
|
|
if (idx >= 0) {
|
|
return path.basename(fullpath.substring(0, idx))
|
|
}
|
|
}
|
|
return path.basename(fullpath)
|
|
}
|
|
|
|
const finders = {
|
|
darwin (cond) {
|
|
return new Promise((resolve, reject) => {
|
|
let cmd
|
|
if ('pid' in cond) {
|
|
cmd = `ps -p ${cond.pid} -ww -o pid,ppid,uid,gid,args`
|
|
} else {
|
|
cmd = 'ps ax -ww -o pid,ppid,uid,gid,args'
|
|
}
|
|
|
|
utils.exec(cmd, function (err, stdout, stderr) {
|
|
if (err) {
|
|
if ('pid' in cond) {
|
|
// when pid not exists, call `ps -p ...` will cause error, we have to
|
|
// ignore the error and resolve with empty array
|
|
resolve([])
|
|
} else {
|
|
reject(err)
|
|
}
|
|
} else {
|
|
err = stderr.toString().trim()
|
|
if (err) {
|
|
reject(err)
|
|
return
|
|
}
|
|
|
|
const data = utils.stripLine(stdout.toString(), 1)
|
|
const columns = utils.extractColumns(data, [0, 1, 2, 3, 4], 5).filter(column => {
|
|
if (column[0] && cond.pid) {
|
|
return column[0] === String(cond.pid)
|
|
} else if (column[4] && cond.name) {
|
|
return matchName(column[4], cond.name)
|
|
} else {
|
|
return !!column[0]
|
|
}
|
|
})
|
|
|
|
let list = columns.map(column => {
|
|
const cmd = String(column[4])
|
|
const bin = fetchBin(cmd)
|
|
|
|
return {
|
|
pid: parseInt(column[0], 10),
|
|
ppid: parseInt(column[1], 10),
|
|
uid: parseInt(column[2], 10),
|
|
gid: parseInt(column[3], 10),
|
|
name: fetchName(bin),
|
|
bin: bin,
|
|
cmd: column[4]
|
|
}
|
|
})
|
|
|
|
if (cond.strict && cond.name) {
|
|
list = list.filter(item => item.name === cond.name)
|
|
}
|
|
|
|
resolve(list)
|
|
}
|
|
})
|
|
})
|
|
},
|
|
linux: 'darwin',
|
|
sunos: 'darwin',
|
|
freebsd: 'darwin',
|
|
win32 (cond) {
|
|
return new Promise((resolve, reject) => {
|
|
const cmd = 'Get-CimInstance -className win32_process | select Name,ProcessId,ParentProcessId,CommandLine,ExecutablePath'
|
|
const lines = []
|
|
|
|
const proc = utils.spawn('powershell.exe', ['/c', cmd], { detached: false, windowsHide: true })
|
|
proc.stdout.on('data', data => {
|
|
lines.push(data.toString())
|
|
})
|
|
proc.on('close', code => {
|
|
if (code !== 0) {
|
|
return reject(new Error('Command \'' + cmd + '\' terminated with code: ' + code))
|
|
}
|
|
const list = utils.parseTable(lines.join(''))
|
|
.filter(row => {
|
|
if ('pid' in cond) {
|
|
return row.ProcessId === String(cond.pid)
|
|
} else if (cond.name) {
|
|
const rowName = row.Name || '' // fix #40
|
|
if (cond.strict) {
|
|
return rowName === cond.name || (rowName.endsWith('.exe') && rowName.slice(0, -4) === cond.name)
|
|
} else {
|
|
// fix #9
|
|
return matchName(row.CommandLine || rowName, cond.name)
|
|
}
|
|
} else {
|
|
return true
|
|
}
|
|
})
|
|
.map(row => ({
|
|
pid: parseInt(row.ProcessId, 10),
|
|
ppid: parseInt(row.ParentProcessId, 10),
|
|
// uid: void 0,
|
|
// gid: void 0,
|
|
bin: row.ExecutablePath,
|
|
name: row.Name || '',
|
|
cmd: row.CommandLine
|
|
}))
|
|
resolve(list)
|
|
})
|
|
})
|
|
},
|
|
android (cond) {
|
|
return new Promise((resolve, reject) => {
|
|
const cmd = 'ps'
|
|
|
|
utils.exec(cmd, function (err, stdout, stderr) {
|
|
if (err) {
|
|
if ('pid' in cond) {
|
|
// when pid not exists, call `ps -p ...` will cause error, we have to
|
|
// ignore the error and resolve with empty array
|
|
resolve([])
|
|
} else {
|
|
reject(err)
|
|
}
|
|
} else {
|
|
err = stderr.toString().trim()
|
|
if (err) {
|
|
reject(err)
|
|
return
|
|
}
|
|
|
|
const data = utils.stripLine(stdout.toString(), 1)
|
|
const columns = utils.extractColumns(data, [0, 3], 4).filter(column => {
|
|
if (column[0] && cond.pid) {
|
|
return column[0] === String(cond.pid)
|
|
} else if (column[1] && cond.name) {
|
|
return matchName(column[1], cond.name)
|
|
} else {
|
|
return !!column[0]
|
|
}
|
|
})
|
|
|
|
let list = columns.map(column => {
|
|
const cmd = String(column[1])
|
|
const bin = fetchBin(cmd)
|
|
|
|
return {
|
|
pid: parseInt(column[0], 10),
|
|
// ppid: void 0,
|
|
// uid: void 0,
|
|
// gid: void 0,
|
|
name: fetchName(bin),
|
|
bin,
|
|
cmd
|
|
}
|
|
})
|
|
|
|
if (cond.strict && cond.name) {
|
|
list = list.filter(item => item.name === cond.name)
|
|
}
|
|
|
|
resolve(list)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function findProcess (cond) {
|
|
const platform = process.platform
|
|
|
|
return new Promise((resolve, reject) => {
|
|
if (!(platform in finders)) {
|
|
return reject(new Error(`platform ${platform} is unsupported`))
|
|
}
|
|
|
|
let find = finders[platform]
|
|
if (typeof find === 'string') {
|
|
find = finders[find]
|
|
}
|
|
|
|
find(cond).then(resolve, reject)
|
|
})
|
|
}
|
|
|
|
module.exports = findProcess
|