74 lines
2.2 KiB
JavaScript
74 lines
2.2 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
exports = module.exports = sudo;
|
||
|
|
||
|
var spawn = require('child_process').spawn;
|
||
|
var read = require('read');
|
||
|
var inpathSync = require('inpath').sync;
|
||
|
var pidof = require('pidof');
|
||
|
|
||
|
var path = process.env['PATH'].split(':');
|
||
|
var sudoBin = inpathSync('sudo', path);
|
||
|
|
||
|
var cachedPassword;
|
||
|
var lastAnswer;
|
||
|
|
||
|
function sudo(command, options) {
|
||
|
var prompt = '#node-sudo-passwd#';
|
||
|
var prompts = 0;
|
||
|
|
||
|
var args = [ '-S', '-p', prompt ];
|
||
|
args.push.apply(args, command);
|
||
|
|
||
|
// The binary is the first non-dashed parameter to sudo
|
||
|
var bin = command.filter(function (i) { return i.indexOf('-') !== 0; })[0];
|
||
|
|
||
|
var options = options || {};
|
||
|
var spawnOptions = options.spawnOptions || {};
|
||
|
spawnOptions.stdio = 'pipe';
|
||
|
|
||
|
var child = spawn(sudoBin, args, spawnOptions);
|
||
|
|
||
|
// Wait for the sudo:d binary to start up
|
||
|
function waitForStartup(err, pid) {
|
||
|
if (err) {
|
||
|
throw new Error('Couldn\'t start ' + bin);
|
||
|
}
|
||
|
|
||
|
if (pid || child.exitCode !== null) {
|
||
|
child.emit('started');
|
||
|
} else {
|
||
|
setTimeout(function () {
|
||
|
pidof(bin, waitForStartup);
|
||
|
}, 100);
|
||
|
}
|
||
|
}
|
||
|
pidof(bin, waitForStartup);
|
||
|
|
||
|
// FIXME: Remove this handler when the child has successfully started
|
||
|
child.stderr.on('data', function (data) {
|
||
|
var lines = data.toString().trim().split('\n');
|
||
|
lines.forEach(function (line) {
|
||
|
if (line === prompt) {
|
||
|
if (++prompts > 1) {
|
||
|
// The previous entry must have been incorrect, since sudo asks again.
|
||
|
cachedPassword = null;
|
||
|
}
|
||
|
|
||
|
if (options.cachePassword && cachedPassword) {
|
||
|
child.stdin.write(cachedPassword + '\n');
|
||
|
} else {
|
||
|
read({ prompt: options.prompt || 'sudo requires your password: ', silent: true }, function (error, answer) {
|
||
|
child.stdin.write(answer + '\n');
|
||
|
if (options.cachePassword) {
|
||
|
cachedPassword = answer;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
return child;
|
||
|
}
|