diff --git a/src/shell.js b/src/shell.js index e3eda97b3..a9d18cd68 100644 --- a/src/shell.js +++ b/src/shell.js @@ -1,9 +1,10 @@ 'use strict'; exports = module.exports = { - sudo: sudo, exec: exec, - execSync: execSync + execSync: execSync, + sudo: sudo, + sudoDetached: sudoDetached }; var assert = require('assert'), @@ -71,3 +72,34 @@ function sudo(tag, args, callback) { cp.stdin.end(); } +function sudoDetached(tag, args, callback) { + assert.strictEqual(typeof tag, 'string'); + assert(util.isArray(args)); + assert.strictEqual(typeof callback, 'function'); + + callback = once(callback); // exit may or may not be called after an 'error' + + debug(tag + ' sudoDetached: %s %s', SUDO, args.join(' ')); + + var cp = child_process.spawn(SUDO, [ '-S' ].concat(args), { detached: true }); + cp.stdout.on('data', function (data) { + debug(tag + ' (stdout): %s', data.toString('utf8')); + }); + + cp.stderr.on('data', function (data) { + debug(tag + ' (stderr): %s', data.toString('utf8')); + }); + + cp.on('exit', function (code, signal) { + if (code || signal) debug(tag + ' code: %s, signal: %s', code, signal); + + callback(code === 0 ? null : new Error(util.format(tag + ' exited with error %s signal %s', code, signal))); + }); + + cp.on('error', function (error) { + debug(tag + ' code: %s, signal: %s', error.code, error.signal); + callback(error); + }); + + return cp; +}