Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@fengmk2/ps-tree

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fengmk2/ps-tree - npm Package Compare versions

Comparing version
1.2.0
to
2.0.0
+15
bin/ps-tree.cjs
#!/usr/bin/env node
//
// Change the default parent PID if running
// under Windows.
//
let ppid = 1;
if (process.platform === 'win32') {
ppid = 0;
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('..').psTree(process.argv[2] || ppid).then(children => {
console.log(children);
});
export interface PSTreeChild {
PPID: string;
PID: string;
STAT: string;
COMMAND: string;
}
export declare function psTree(pid: number | string, callback?: (err: Error | null, children?: PSTreeChild[]) => void): Promise<PSTreeChild[]> | undefined;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.psTree = psTree;
const node_child_process_1 = require("node:child_process");
const event_stream_1 = __importDefault(require("event-stream"));
function psTree(pid, callback) {
const promise = childrenOfPid(pid);
if (!callback) {
return promise;
}
// keep compatibility for `psTree(pid, callback)`
promise.then(children => callback(null, children))
.catch(err => callback(err));
}
function childrenOfPid(pid) {
return new Promise((resolve, reject) => {
let headers;
if (typeof pid === 'number') {
pid = String(pid);
}
//
// The `ps-tree` module behaves differently on *nix vs. Windows
// by spawning different programs and parsing their output.
//
// Linux:
// 1. " <defunct> " need to be striped
// ```bash
// $ ps -A -o comm,ppid,pid,stat
// COMMAND PPID PID STAT
// bbsd 2899 16958 Ss
// watch <defunct> 1914 16964 Z
// ps 20688 16965 R+
// ```
//
// Darwin:
// $ ps -A -o comm,ppid,pid,stat
// COMM PPID PID STAT
// /sbin/launchd 0 1 Ss
// /usr/libexec/Use 1 43 Ss
//
// Win32:
// 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status)
// 2. The order of head columns is fixed
// ```shell
// > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status
// Name ParentProcessId ProcessId Status
// System Idle Process 0 0
// System 0 4
// smss.exe 4 228
// ```
let processLister;
if (process.platform === 'win32') {
// See also: https://github.com/nodejs/node-v0.x-archive/issues/2318
processLister = (0, node_child_process_1.spawn)('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']);
}
else {
processLister = (0, node_child_process_1.spawn)('ps', ['-A', '-o', 'ppid,pid,stat,comm']);
}
event_stream_1.default.pipeline(
// spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout,
processLister.stdout, event_stream_1.default.split(), event_stream_1.default.map((line, cb) => {
const columns = line.trim().split(/\s+/);
if (!headers) {
headers = columns;
//
// Rename Win32 header name, to as same as the linux, for compatible.
//
headers = headers.map(normalizeHeader);
return cb();
}
const row = {};
// For each header
const h = headers.slice();
while (h.length) {
const key = h.shift();
row[key] = h.length ? columns.shift() : columns.join(' ');
}
return cb(null, row);
}), event_stream_1.default.writeArray((_err, ps) => {
const parents = {};
const children = [];
parents[pid] = true;
ps.forEach((proc) => {
if (parents[proc.PPID]) {
parents[proc.PID] = true;
children.push(proc);
}
});
resolve(children);
})).on('error', reject);
});
}
/**
* Normalizes the given header `str` from the Windows
* title to the *nix title.
*
* @param {string} str Header string to normalize
*/
function normalizeHeader(str) {
switch (str) {
case 'Name': // for win32
case 'COMM': // for darwin
return 'COMMAND';
case 'ParentProcessId':
return 'PPID';
case 'ProcessId':
return 'PID';
case 'Status':
return 'STAT';
default:
return str;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFVQSx3QkFTQztBQW5CRCwyREFBMkU7QUFDM0UsZ0VBQThCO0FBUzlCLFNBQWdCLE1BQU0sQ0FBQyxHQUFvQixFQUFFLFFBQWdFO0lBQzNHLE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDZCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQsaURBQWlEO0lBQ2pELE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQy9DLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFvQjtJQUN6QyxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JDLElBQUksT0FBaUIsQ0FBQztRQUV0QixJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzVCLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDcEIsQ0FBQztRQUVELEVBQUU7UUFDRiwrREFBK0Q7UUFDL0QsMkRBQTJEO1FBQzNELEVBQUU7UUFDRixTQUFTO1FBQ1Qsc0NBQXNDO1FBQ3RDLFVBQVU7UUFDVixnQ0FBZ0M7UUFDaEMsbUNBQW1DO1FBQ25DLGlDQUFpQztRQUNqQyxnQ0FBZ0M7UUFDaEMsaUNBQWlDO1FBQ2pDLE1BQU07UUFDTixFQUFFO1FBQ0YsVUFBVTtRQUNWLGdDQUFnQztRQUNoQyxvQ0FBb0M7UUFDcEMsa0NBQWtDO1FBQ2xDLGtDQUFrQztRQUNsQyxFQUFFO1FBQ0Ys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
{
"type": "commonjs"
}
export interface PSTreeChild {
PPID: string;
PID: string;
STAT: string;
COMMAND: string;
}
export declare function psTree(pid: number | string, callback?: (err: Error | null, children?: PSTreeChild[]) => void): Promise<PSTreeChild[]> | undefined;
import { spawn } from 'node:child_process';
import es from 'event-stream';
export function psTree(pid, callback) {
const promise = childrenOfPid(pid);
if (!callback) {
return promise;
}
// keep compatibility for `psTree(pid, callback)`
promise.then(children => callback(null, children))
.catch(err => callback(err));
}
function childrenOfPid(pid) {
return new Promise((resolve, reject) => {
let headers;
if (typeof pid === 'number') {
pid = String(pid);
}
//
// The `ps-tree` module behaves differently on *nix vs. Windows
// by spawning different programs and parsing their output.
//
// Linux:
// 1. " <defunct> " need to be striped
// ```bash
// $ ps -A -o comm,ppid,pid,stat
// COMMAND PPID PID STAT
// bbsd 2899 16958 Ss
// watch <defunct> 1914 16964 Z
// ps 20688 16965 R+
// ```
//
// Darwin:
// $ ps -A -o comm,ppid,pid,stat
// COMM PPID PID STAT
// /sbin/launchd 0 1 Ss
// /usr/libexec/Use 1 43 Ss
//
// Win32:
// 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status)
// 2. The order of head columns is fixed
// ```shell
// > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status
// Name ParentProcessId ProcessId Status
// System Idle Process 0 0
// System 0 4
// smss.exe 4 228
// ```
let processLister;
if (process.platform === 'win32') {
// See also: https://github.com/nodejs/node-v0.x-archive/issues/2318
processLister = spawn('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']);
}
else {
processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']);
}
es.pipeline(
// spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout,
processLister.stdout, es.split(), es.map((line, cb) => {
const columns = line.trim().split(/\s+/);
if (!headers) {
headers = columns;
//
// Rename Win32 header name, to as same as the linux, for compatible.
//
headers = headers.map(normalizeHeader);
return cb();
}
const row = {};
// For each header
const h = headers.slice();
while (h.length) {
const key = h.shift();
row[key] = h.length ? columns.shift() : columns.join(' ');
}
return cb(null, row);
}), es.writeArray((_err, ps) => {
const parents = {};
const children = [];
parents[pid] = true;
ps.forEach((proc) => {
if (parents[proc.PPID]) {
parents[proc.PID] = true;
children.push(proc);
}
});
resolve(children);
})).on('error', reject);
});
}
/**
* Normalizes the given header `str` from the Windows
* title to the *nix title.
*
* @param {string} str Header string to normalize
*/
function normalizeHeader(str) {
switch (str) {
case 'Name': // for win32
case 'COMM': // for darwin
return 'COMMAND';
case 'ParentProcessId':
return 'PPID';
case 'ProcessId':
return 'PID';
case 'Status':
return 'STAT';
default:
return str;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBa0MsTUFBTSxvQkFBb0IsQ0FBQztBQUMzRSxPQUFPLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFTOUIsTUFBTSxVQUFVLE1BQU0sQ0FBQyxHQUFvQixFQUFFLFFBQWdFO0lBQzNHLE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDZCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQsaURBQWlEO0lBQ2pELE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQy9DLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFvQjtJQUN6QyxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JDLElBQUksT0FBaUIsQ0FBQztRQUV0QixJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzVCLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDcEIsQ0FBQztRQUVELEVBQUU7UUFDRiwrREFBK0Q7UUFDL0QsMkRBQTJEO1FBQzNELEVBQUU7UUFDRixTQUFTO1FBQ1Qsc0NBQXNDO1FBQ3RDLFVBQVU7UUFDVixnQ0FBZ0M7UUFDaEMsbUNBQW1DO1FBQ25DLGlDQUFpQztRQUNqQyxnQ0FBZ0M7UUFDaEMsaUNBQWlDO1FBQ2pDLE1BQU07UUFDTixFQUFFO1FBQ0YsVUFBVTtRQUNWLGdDQUFnQztRQUNoQyxvQ0FBb0M7UUFDcEMs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
{
"type": "module"
}
{
"name": "@fengmk2/ps-tree",
"version": "2.0.0"
}
import { spawn, ChildProcessWithoutNullStreams } from 'node:child_process';
import es from 'event-stream';
export interface PSTreeChild {
PPID: string;
PID: string;
STAT: string;
COMMAND: string;
}
export function psTree(pid: number | string, callback?: (err: Error | null, children?: PSTreeChild[]) => void) {
const promise = childrenOfPid(pid);
if (!callback) {
return promise;
}
// keep compatibility for `psTree(pid, callback)`
promise.then(children => callback(null, children))
.catch(err => callback(err));
}
function childrenOfPid(pid: number | string): Promise<PSTreeChild[]> {
return new Promise((resolve, reject) => {
let headers: string[];
if (typeof pid === 'number') {
pid = String(pid);
}
//
// The `ps-tree` module behaves differently on *nix vs. Windows
// by spawning different programs and parsing their output.
//
// Linux:
// 1. " <defunct> " need to be striped
// ```bash
// $ ps -A -o comm,ppid,pid,stat
// COMMAND PPID PID STAT
// bbsd 2899 16958 Ss
// watch <defunct> 1914 16964 Z
// ps 20688 16965 R+
// ```
//
// Darwin:
// $ ps -A -o comm,ppid,pid,stat
// COMM PPID PID STAT
// /sbin/launchd 0 1 Ss
// /usr/libexec/Use 1 43 Ss
//
// Win32:
// 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status)
// 2. The order of head columns is fixed
// ```shell
// > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status
// Name ParentProcessId ProcessId Status
// System Idle Process 0 0
// System 0 4
// smss.exe 4 228
// ```
let processLister: ChildProcessWithoutNullStreams;
if (process.platform === 'win32') {
// See also: https://github.com/nodejs/node-v0.x-archive/issues/2318
processLister = spawn('wmic.exe', [ 'PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status' ]);
} else {
processLister = spawn('ps', [ '-A', '-o', 'ppid,pid,stat,comm' ]);
}
es.pipeline(
// spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout,
processLister.stdout as any,
es.split(),
es.map((line: string, cb: (...args: any[]) => void) => { // this could parse alot of unix command output
const columns = line.trim().split(/\s+/);
if (!headers) {
headers = columns;
//
// Rename Win32 header name, to as same as the linux, for compatible.
//
headers = headers.map(normalizeHeader);
return cb();
}
const row: Record<string, string | undefined> = {};
// For each header
const h = headers.slice();
while (h.length) {
const key = h.shift();
row[key!] = h.length ? columns.shift() : columns.join(' ');
}
return cb(null, row);
}),
es.writeArray((_err: any, ps: any[]) => {
const parents: Record<string, true> = {};
const children: PSTreeChild[] = [];
parents[pid] = true;
ps.forEach((proc: any) => {
if (parents[proc.PPID]) {
parents[proc.PID] = true;
children.push(proc);
}
});
resolve(children);
}),
).on('error', reject);
});
}
/**
* Normalizes the given header `str` from the Windows
* title to the *nix title.
*
* @param {string} str Header string to normalize
*/
function normalizeHeader(str: string) {
switch (str) {
case 'Name': // for win32
case 'COMM': // for darwin
return 'COMMAND';
case 'ParentProcessId':
return 'PPID';
case 'ProcessId':
return 'PID';
case 'Status':
return 'STAT';
default:
return str;
}
}
+1
-0
The MIT License (MIT)
Copyright (c) 2014 Domenic Tarr, Charlie Robbins & the Contributors
Copyright (c) 2024-present fengmk2 and the Contributors

@@ -5,0 +6,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

+60
-24
{
"name": "@fengmk2/ps-tree",
"version": "1.2.0",
"version": "2.0.0",
"publishConfig": {
"access": "public"
},
"description": "Get all children of a pid",
"description": "Get all children of a pid and support CommonJS and ESM both",
"license": "MIT",
"homepage": "http://github.com/indexzero/ps-tree#readme",
"repository": "github:indexzero/ps-tree",
"homepage": "http://github.com/fengmk2/ps-tree#readme",
"repository": "github:fengmk2/ps-tree",
"bugs": {
"url": "https://github.com/indexzero/ps-tree/issues",
"email": "charlie.robbins@gmail.com"
"url": "https://github.com/fengmk2/ps-tree/issues"
},

@@ -27,27 +26,64 @@ "author": "Charlie Robbins <charlie.robbins@gmail.com>",

],
"main": "index.js",
"bin": {
"ps-tree": "./bin/ps-tree.js"
"ps-tree": "./bin/ps-tree.cjs"
},
"files": [
"bin",
"index.js"
],
"dependencies": {
"event-stream": "^4.0.1"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.1",
"@eggjs/tsconfig": "1",
"@types/event-stream": "^4.0.5",
"@types/mocha": "10",
"@types/node": "22",
"c8": "^10.1.3",
"egg-bin": "6",
"eslint": "8",
"eslint-config-egg": "14",
"tape": "^4.17.0",
"tree-kill": "^1.1.0",
"tshy": "3",
"tshy-after": "1",
"typescript": "5"
},
"engines": {
"node": ">= 0.10"
"node": ">= 18.19.0"
},
"scripts": {
"test": "istanbul cover node_modules/tape/bin/tape test/test.js",
"coverage": "cross-env CODECLIMATE_REPO_TOKEN=84436b4f13c70ace9c62e7f04928bf23c234eb212c0232d39d7fb1535beb2da5 node_modules/.bin/codeclimate-test-reporter < coverage/lcov.info"
"lint": "eslint --cache src --ext .ts",
"pretest": "npm run lint -- --fix && npm run prepublishOnly",
"test": "npm run test-local",
"test-local": "tape test/test.cjs",
"preci": "npm run lint && npm run prepublishOnly",
"ci": "c8 tape test/test.cjs && attw --pack",
"prepublishOnly": "tshy && tshy-after"
},
"dependencies": {
"event-stream": "=3.3.4"
"type": "module",
"tshy": {
"exports": {
".": "./src/index.ts",
"./package.json": "./package.json"
}
},
"devDependencies": {
"codeclimate-test-reporter": "^0.5.0",
"cross-env": "^2.0.1",
"istanbul": "^0.4.5",
"tape": "^4.9.0",
"tree-kill": "^1.1.0"
}
"exports": {
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.js"
}
},
"./package.json": "./package.json"
},
"files": [
"dist",
"src",
"bin"
],
"types": "./dist/commonjs/index.d.ts",
"main": "./dist/commonjs/index.js",
"module": "./dist/esm/index.js"
}
+49
-26

@@ -1,10 +0,21 @@

# ps-tree
# @fengmk2/ps-tree
[![Build Status](https://github.com/indexzero/ps-tree/actions/workflows/ci-test.yml/badge.svg)](https://github.com/indexzero/ps-tree/actions/workflows/ci-test.yml)
[![Code Climate](https://codeclimate.com/github/indexzero/ps-tree/badges/gpa.svg)](https://codeclimate.com/github/indexzero/ps-tree)
[![Test Coverage](https://codeclimate.com/github/indexzero/ps-tree/badges/coverage.svg)](https://codeclimate.com/github/indexzero/ps-tree)
[![npm Version](https://img.shields.io/npm/v/ps-tree.svg)](https://www.npmjs.com/package/ps-tree)
[![Node.js Version](https://img.shields.io/node/v/ps-tree.svg?style=flat)](http://nodejs.org/download/)
[![Dependency Status](https://david-dm.org/indexzero/ps-tree.svg)](https://david-dm.org/indexzero/ps-tree)
[![NPM version][npm-image]][npm-url]
[![Node.js CI](https://github.com/fengmk2/ps-tree/actions/workflows/nodejs.yml/badge.svg)](https://github.com/fengmk2/ps-tree/actions/workflows/nodejs.yml)
[![Test coverage][codecov-image]][codecov-url]
[![Known Vulnerabilities][snyk-image]][snyk-url]
[![npm download][download-image]][download-url]
[![Node.js Version](https://img.shields.io/node/v/@fengmk2/ps-tree.svg?style=flat)](http://nodejs.org/download/)
[npm-image]: https://img.shields.io/npm/v/@fengmk2/ps-tree.svg?style=flat-square
[npm-url]: https://npmjs.org/package/@fengmk2/ps-tree
[codecov-image]: https://codecov.io/github/fengmk2/ps-tree/coverage.svg?branch=master
[codecov-url]: https://codecov.io/github/fengmk2/ps-tree?branch=master
[snyk-image]: https://snyk.io/test/npm/@fengmk2/ps-tree/badge.svg?style=flat-square
[snyk-url]: https://snyk.io/test/npm/@fengmk2/ps-tree
[download-image]: https://img.shields.io/npm/dm/@fengmk2/ps-tree.svg?style=flat-square
[download-url]: https://npmjs.org/package/@fengmk2/ps-tree
> Fork [indexzero/ps-tree](https://github.com/indexzero/ps-tree), refactor in TypeScript to support CommonJS and ESM both
Sometimes you cannot kill child processes like you would expect, this a feature of UNIX.

@@ -17,7 +28,6 @@

``` js
var cp = require('child_process'),
psTree = require('ps-tree');
```ts
import cp from 'node:child_process';
var child = cp.exec("node -e 'while (true);'", function () {...});
const child = cp.exec("node -e 'while (true);'", function () {...});

@@ -30,4 +40,4 @@ // This will not actually kill the child it will kill the `sh` process.

``` js
function exec (cmd, cb) {
```js
function exec(cmd, cb) {
spawn('sh', ['-c', cmd]);

@@ -43,23 +53,26 @@ ...

``` js
var cp = require('child_process'),
psTree = require('ps-tree');
```js
import cp from 'node:child_process';
import { psTree } from '@fengmk2/ps-tree';
var child = cp.exec("node -e 'while (true);'", function () { /*...*/ });
const child = cp.exec("node -e 'while (true);'", function () { /*...*/ });
psTree(child.pid, function (err, children) {
cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID })));
});
psTree(child.pid)
.then(children => {
cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID })));
}).catch(err => {
console.error(err);
});
```
If you prefer to run **psTree** from the command line, use: `node ./bin/ps-tree.js`
If you prefer to run **psTree** from the command line, use: `node ./bin/ps-tree.cjs`
## Cross Platform support
The `ps-tree` module behaves differently on *nix vs. Windows by spawning different programs and parsing their output. This is based on `process.platform` and not on checking to see if a `ps` compatible program exists on the system.
#### *nix
### *nix
1. " <defunct> " need to be striped
1. `" <defunct> "` need to be striped
```bash

@@ -74,4 +87,6 @@ $ ps -A -o comm,ppid,pid,stat

### Windows
1. `wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status)`
2. The order of head columns is fixed
```shell

@@ -87,3 +102,3 @@ > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status

1. " " need to be striped
1. `" "` need to be striped

@@ -97,2 +112,10 @@ ```shell

### LICENSE: MIT
### LICENSE
[MIT](LICENSE)
## Contributors
[![Contributors](https://contrib.rocks/image?repo=fengmk2/ps-tree)](https://github.com/fengmk2/ps-tree/graphs/contributors)
Made with [contributors-img](https://contrib.rocks).
#!/usr/bin/env node
'use strict';
//
// Change the default parent PID if running
// under Windows.
//
var ppid = 1;
if (process.platform === 'win32') {
ppid = 0;
}
require('../')(process.argv[2] || ppid, function (err, data) {
console.log(data);
});
'use strict';
var spawn = require('child_process').spawn,
es = require('event-stream');
module.exports = function childrenOfPid(pid, callback) {
var headers = null;
if (typeof callback !== 'function') {
throw new Error('childrenOfPid(pid, callback) expects callback');
}
if (typeof pid === 'number') {
pid = pid.toString();
}
//
// The `ps-tree` module behaves differently on *nix vs. Windows
// by spawning different programs and parsing their output.
//
// Linux:
// 1. " <defunct> " need to be striped
// ```bash
// $ ps -A -o comm,ppid,pid,stat
// COMMAND PPID PID STAT
// bbsd 2899 16958 Ss
// watch <defunct> 1914 16964 Z
// ps 20688 16965 R+
// ```
//
// Darwin:
// $ ps -A -o comm,ppid,pid,stat
// COMM PPID PID STAT
// /sbin/launchd 0 1 Ss
// /usr/libexec/Use 1 43 Ss
//
// Win32:
// 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status)
// 2. The order of head columns is fixed
// ```shell
// > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status
// Name ParentProcessId ProcessId Status
// System Idle Process 0 0
// System 0 4
// smss.exe 4 228
// ```
var processLister;
if (process.platform === 'win32') {
// See also: https://github.com/nodejs/node-v0.x-archive/issues/2318
processLister = spawn('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']);
} else {
processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']);
}
es.connect(
// spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout,
processLister.stdout,
es.split(),
es.map(function (line, cb) { //this could parse alot of unix command output
var columns = line.trim().split(/\s+/);
if (!headers) {
headers = columns;
//
// Rename Win32 header name, to as same as the linux, for compatible.
//
headers = headers.map(normalizeHeader);
return cb();
}
var row = {};
// For each header
var h = headers.slice();
while (h.length) {
row[h.shift()] = h.length ? columns.shift() : columns.join(' ');
}
return cb(null, row);
}),
es.writeArray(function (err, ps) {
var parents = {},
children = [];
parents[pid] = true;
ps.forEach(function (proc) {
if (parents[proc.PPID]) {
parents[proc.PID] = true;
children.push(proc)
}
});
callback(null, children);
})
).on('error', callback)
}
/**
* Normalizes the given header `str` from the Windows
* title to the *nix title.
*
* @param {string} str Header string to normalize
*/
function normalizeHeader(str) {
switch (str) {
case 'Name': // for win32
case 'COMM': // for darwin
return 'COMMAND';
break;
case 'ParentProcessId':
return 'PPID';
break;
case 'ProcessId':
return 'PID';
break;
case 'Status':
return 'STAT';
break;
default:
return str
}
}