/* * @Author: zoujie.wzj * @Date: 2016-01-22 19:27:17 * @Last Modified by: Ayon Lee * @Last Modified on: 2018-10-19 */ 'use strict' // find pid by port const os = require('os') const fs = require('fs') const utils = require('./utils') const ensureDir = (path) => new Promise((resolve, reject) => { if (fs.existsSync(path)) { resolve() } else { fs.mkdir(path, err => { err ? reject(err) : resolve() }) } }) const finders = { darwin (port) { return new Promise((resolve, reject) => { utils.exec('netstat -anv -p TCP && netstat -anv -p UDP', function (err, stdout, stderr) { if (err) { reject(err) } else { err = stderr.toString().trim() if (err) { reject(err) return } // replace header const data = utils.stripLine(stdout.toString(), 2) const found = utils.extractColumns(data, [0, 3, 8], 10) .filter(row => { return !!String(row[0]).match(/^(udp|tcp)/) }) .find(row => { const matches = String(row[1]).match(/\.(\d+)$/) if (matches && matches[1] === String(port)) { return true } }) if (found && found[2].length) { resolve(parseInt(found[2], 10)) } else { reject(new Error(`pid of port (${port}) not found`)) } } }) }) }, freebsd: 'darwin', sunos: 'darwin', linux (port) { return new Promise((resolve, reject) => { const cmd = 'netstat -tunlp' utils.exec(cmd, function (err, stdout, stderr) { if (err) { reject(err) } else { const warn = stderr.toString().trim() if (warn) { // netstat -p ouputs warning if user is no-root console.warn(warn) } // replace header const data = utils.stripLine(stdout.toString(), 2) const columns = utils.extractColumns(data, [3, 6], 7).find(column => { const matches = String(column[0]).match(/:(\d+)$/) if (matches && matches[1] === String(port)) { return true } }) if (columns && columns[1]) { const pid = columns[1].split('/', 1)[0] if (pid.length) { resolve(parseInt(pid, 10)) } else { reject(new Error(`pid of port (${port}) not found`)) } } else { reject(new Error(`pid of port (${port}) not found`)) } } }) }) }, win32 (port) { return new Promise((resolve, reject) => { utils.exec('netstat -ano', function (err, stdout, stderr) { if (err) { reject(err) } else { err = stderr.toString().trim() if (err) { reject(err) return } // replace header const data = utils.stripLine(stdout.toString(), 4) const columns = utils.extractColumns(data, [1, 4], 5).find(column => { const matches = String(column[0]).match(/:(\d+)$/) if (matches && matches[1] === String(port)) { return true } }) if (columns && columns[1].length && parseInt(columns[1], 10) > 0) { resolve(parseInt(columns[1], 10)) } else { reject(new Error(`pid of port (${port}) not found`)) } } }) }) }, android (port) { return new Promise((resolve, reject) => { // on Android Termux, an warning will be emitted when executing `netstat` // with option `-p` says 'showing only processes with your user ID', but // it can still fetch the information we need. However, NodeJS treat this // warning as an error, `util.exec()` will get nothing but the error. To // get the true output of the command, we need to save it to a tmpfile and // read that file instead. const dir = os.tmpdir() + '/.find-process' const file = dir + '/' + process.pid const cmd = 'netstat -tunp >> "' + file + '"' ensureDir(dir).then(() => { utils.exec(cmd, () => { fs.readFile(file, 'utf8', (err, data) => { fs.unlink(file, () => { }) if (err) { reject(err) } else { data = utils.stripLine(data, 2) const columns = utils.extractColumns(data, [3, 6], 7).find(column => { const matches = String(column[0]).match(/:(\d+)$/) if (matches && matches[1] === String(port)) { return true } }) if (columns && columns[1]) { const pid = columns[1].split('/', 1)[0] if (pid.length) { resolve(parseInt(pid, 10)) } else { reject(new Error(`pid of port (${port}) not found`)) } } else { reject(new Error(`pid of port (${port}) not found`)) } } }) }) }) }) } } function findPidByPort (port) { const platform = process.platform return new Promise((resolve, reject) => { if (!(platform in finders)) { return reject(new Error(`platform ${platform} is unsupported`)) } let findPid = finders[platform] if (typeof findPid === 'string') { findPid = finders[findPid] } findPid(port).then(resolve, reject) }) } module.exports = findPidByPort