mirror of
https://github.com/nodejs/node.git
synced 2024-11-30 07:27:22 +01:00
f8a3cf980f
The child process 'exit' was returning the status of the process, rather than the exit code. This patch properly deconstructs the status into the exit code and the term signal a process may have received. See: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Watcher_Specific_Functions_and_Data_-5 and waitpid(2)
155 lines
3.9 KiB
JavaScript
155 lines
3.9 KiB
JavaScript
var inherits = require('sys').inherits;
|
|
var EventEmitter = require('events').EventEmitter;
|
|
var Stream = require('net').Stream;
|
|
var InternalChildProcess = process.binding('child_process').ChildProcess;
|
|
|
|
|
|
var spawn = exports.spawn = function (path, args, env) {
|
|
var child = new ChildProcess();
|
|
child.spawn(path, args, env);
|
|
return child;
|
|
};
|
|
|
|
exports.exec = function (command /*, options, callback */) {
|
|
if (arguments.length < 3) {
|
|
return exports.execFile("/bin/sh", ["-c", command], arguments[1]);
|
|
} else {
|
|
return exports.execFile("/bin/sh", ["-c", command], arguments[1], arguments[2]);
|
|
}
|
|
};
|
|
|
|
exports.execFile = function (file, args /*, options, callback */) {
|
|
var options = { encoding: 'utf8'
|
|
, timeout: 0
|
|
, maxBuffer: 200*1024
|
|
, killSignal: 'SIGKILL'
|
|
};
|
|
|
|
var callback = arguments[arguments.length-1];
|
|
|
|
if (typeof arguments[2] == 'object') {
|
|
var keys = Object.keys(options);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var k = keys[i];
|
|
if (arguments[2][k] !== undefined) options[k] = arguments[2][k];
|
|
}
|
|
}
|
|
|
|
var child = spawn(file, args);
|
|
var stdout = "";
|
|
var stderr = "";
|
|
var killed = false;
|
|
|
|
var timeoutId;
|
|
if (options.timeout > 0) {
|
|
timeoutId = setTimeout(function () {
|
|
if (!killed) {
|
|
child.kill(options.killSignal);
|
|
killed = true;
|
|
timeoutId = null;
|
|
}
|
|
}, options.timeout);
|
|
}
|
|
|
|
child.stdout.setEncoding(options.encoding);
|
|
child.stderr.setEncoding(options.encoding);
|
|
|
|
child.stdout.addListener("data", function (chunk) {
|
|
stdout += chunk;
|
|
if (!killed && stdout.length > options.maxBuffer) {
|
|
child.kill(options.killSignal);
|
|
killed = true;
|
|
}
|
|
});
|
|
|
|
child.stderr.addListener("data", function (chunk) {
|
|
stderr += chunk;
|
|
if (!killed && stderr.length > options.maxBuffer) {
|
|
child.kill(options.killSignal);
|
|
killed = true
|
|
}
|
|
});
|
|
|
|
child.addListener("exit", function (code, signal) {
|
|
if (timeoutId) clearTimeout(timeoutId);
|
|
if (code === 0 && signal === null) {
|
|
if (callback) callback(null, stdout, stderr);
|
|
} else {
|
|
var e = new Error("Command failed: " + stderr);
|
|
e.killed = killed;
|
|
e.code = code;
|
|
e.signal = signal;
|
|
if (callback) callback(e, stdout, stderr);
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
function ChildProcess () {
|
|
process.EventEmitter.call(this);
|
|
|
|
var self = this;
|
|
|
|
var gotCHLD = false;
|
|
var exitCode;
|
|
var termSignal;
|
|
var internal = this._internal = new InternalChildProcess();
|
|
|
|
var stdin = this.stdin = new Stream();
|
|
var stdout = this.stdout = new Stream();
|
|
var stderr = this.stderr = new Stream();
|
|
|
|
stderr.onend = stdout.onend = function () {
|
|
if (gotCHLD && !stdout.readable && !stderr.readable) {
|
|
self.emit('exit', exitCode, termSignal);
|
|
}
|
|
};
|
|
|
|
internal.onexit = function (code, signal) {
|
|
gotCHLD = true;
|
|
exitCode = code;
|
|
termSignal = signal;
|
|
stdin.end();
|
|
if (!stdout.readable && !stderr.readable) {
|
|
self.emit('exit', exitCode, termSignal);
|
|
}
|
|
};
|
|
|
|
this.__defineGetter__('pid', function () { return internal.pid; });
|
|
}
|
|
inherits(ChildProcess, EventEmitter);
|
|
|
|
|
|
ChildProcess.prototype.kill = function (sig) {
|
|
return this._internal.kill(sig);
|
|
};
|
|
|
|
|
|
ChildProcess.prototype.spawn = function (path, args, env) {
|
|
args = args || [];
|
|
env = env || process.env;
|
|
var envPairs = [];
|
|
var keys = Object.keys(env);
|
|
for (var index = 0, keysLength = keys.length; index < keysLength; index++) {
|
|
var key = keys[index];
|
|
envPairs.push(key + "=" + env[key]);
|
|
}
|
|
|
|
var fds = this._internal.spawn(path, args, envPairs);
|
|
|
|
this.stdin.open(fds[0]);
|
|
this.stdin.writable = true;
|
|
this.stdin.readable = false;
|
|
|
|
this.stdout.open(fds[1]);
|
|
this.stdout.writable = false;
|
|
this.stdout.readable = true;
|
|
this.stdout.resume();
|
|
|
|
this.stderr.open(fds[2]);
|
|
this.stderr.writable = false;
|
|
this.stderr.readable = true;
|
|
this.stderr.resume();
|
|
};
|
|
|