Skip to content

Commit ac2cfac

Browse files
fix: correctly parse ps output on linux (#1389)
1 parent 415ae57 commit ac2cfac

File tree

1 file changed

+35
-28
lines changed

1 file changed

+35
-28
lines changed

src/processTree.ts

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
* Copied from https://github.com/microsoft/vscode-node-debug/blob/master/src/node/extension/processTree.ts
66
*--------------------------------------------------------------------------------------------*/
77
/* tslint:disable */
8-
'use strict';
8+
'use strict';
99

10-
import { spawn, ChildProcess } from 'child_process';
10+
import { spawn, ChildProcessWithoutNullStreams } from 'child_process';
1111
import { join } from 'path';
1212

1313
export class ProcessTreeNode {
@@ -68,7 +68,7 @@ export function getProcesses(one: (pid: number, ppid: number, command: string, a
6868

6969
return new Promise((resolve, reject) => {
7070

71-
let proc: ChildProcess;
71+
let proc: ChildProcessWithoutNullStreams;
7272

7373
if (process.platform === 'win32') {
7474

@@ -77,8 +77,8 @@ export function getProcesses(one: (pid: number, ppid: number, command: string, a
7777

7878
const wmic = join(process.env['WINDIR'] || 'C:\\Windows', 'System32', 'wbem', 'WMIC.exe');
7979
proc = spawn(wmic, [ 'process', 'get', 'CommandLine,CreationDate,ParentProcessId,ProcessId' ]);
80-
proc.stdout?.setEncoding('utf8');
81-
proc.stdout?.on('data', lines(line => {
80+
proc.stdout.setEncoding('utf8');
81+
proc.stdout.on('data', lines(line => {
8282
let matches = CMD_PAT.exec(line.trim());
8383
if (matches && matches.length === 5) {
8484
const pid = Number(matches[4]);
@@ -110,8 +110,8 @@ export function getProcesses(one: (pid: number, ppid: number, command: string, a
110110
} else if (process.platform === 'darwin') { // OS X
111111

112112
proc = spawn('/bin/ps', [ '-x', '-o', `pid,ppid,comm=${'a'.repeat(256)},command` ]);
113-
proc.stdout?.setEncoding('utf8');
114-
proc.stdout?.on('data', lines(line => {
113+
proc.stdout.setEncoding('utf8');
114+
proc.stdout.on('data', lines(line => {
115115

116116
const pid = Number(line.substr(0, 5));
117117
const ppid = Number(line.substr(6, 5));
@@ -125,28 +125,31 @@ export function getProcesses(one: (pid: number, ppid: number, command: string, a
125125

126126
} else { // linux
127127

128-
proc = spawn('/bin/ps', [ '-ax', '-o', 'pid,ppid,comm:20,command' ]);
129-
proc.stdout?.setEncoding('utf8');
130-
proc.stdout?.on('data', lines(line => {
131-
132-
const pid = Number(line.substr(0, 5));
133-
const ppid = Number(line.substr(6, 5));
134-
let command = line.substr(12, 20).trim();
135-
let args = line.substr(33);
136-
137-
let pos = args.indexOf(command);
128+
proc = spawn('/bin/ps', [ '-ax', '-o', 'pid:6,ppid:6,comm:20,command' ]); // we specify the column width explicitly
129+
proc.stdout.setEncoding('utf8');
130+
proc.stdout.on('data', lines(line => {
131+
132+
// the following substr arguments must match the column width specified for the "ps" command above
133+
// regular substr is deprecated
134+
const pid = Number(substr(line, 0, 6));
135+
const ppid = Number(substr(line, 7, 6));
136+
const shortName = substr(line, 14, 20).trim()
137+
const fullCommand = substr(line, 35)
138+
139+
let command = shortName;
140+
let args = fullCommand;
141+
142+
const pos = fullCommand.indexOf(shortName);
138143
if (pos >= 0) {
139-
pos = pos + command.length;
140-
while (pos < args.length) {
141-
if (args[pos] === ' ') {
142-
break;
143-
}
144-
pos++;
145-
}
146-
command = args.substr(0, pos);
147-
args = args.substr(pos + 1);
144+
// binaries with spaces in path may not work
145+
// possible solution to read directly from /proc
146+
const commandEndPositionMaybe = fullCommand.indexOf(" ", pos + shortName.length);
147+
const commandEndPosition = commandEndPositionMaybe < 0 ? fullCommand.length : commandEndPositionMaybe;
148+
command = fullCommand.substring(0, commandEndPosition)
149+
args = fullCommand.substring(commandEndPosition).trimStart()
148150
}
149151

152+
150153
if (!isNaN(pid) && !isNaN(ppid)) {
151154
one(pid, ppid, command, args);
152155
}
@@ -157,8 +160,8 @@ export function getProcesses(one: (pid: number, ppid: number, command: string, a
157160
reject(err);
158161
});
159162

160-
proc.stderr?.setEncoding('utf8');
161-
proc.stderr?.on('data', data => {
163+
proc.stderr.setEncoding('utf8');
164+
proc.stderr.on('data', data => {
162165
const e = data.toString();
163166
if (e.indexOf('screen size is bogus') >= 0) {
164167
// ignore this error silently; see https://github.com/microsoft/vscode/issues/75932
@@ -192,3 +195,7 @@ export function getProcesses(one: (pid: number, ppid: number, command: string, a
192195
});
193196
});
194197
}
198+
199+
function substr(str: string, startIndex: number, length?: number) {
200+
return str.slice(startIndex, length != undefined ? startIndex + length : str.length)
201+
}

0 commit comments

Comments
 (0)