From 202dd8387fc60dbff644844db8bb23e02abb7c07 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 10 Jan 2011 16:22:58 -0800 Subject: [PATCH] Add setsid option to child_process --- doc/api/child_processes.markdown | 7 +++++-- lib/child_process.js | 12 ++++++++++-- src/node_child_process.cc | 15 +++++++++++++-- src/node_child_process.h | 8 +++++++- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/doc/api/child_processes.markdown b/doc/api/child_processes.markdown index efbadb0b3f..575486f30d 100644 --- a/doc/api/child_processes.markdown +++ b/doc/api/child_processes.markdown @@ -59,12 +59,15 @@ The third argument is used to specify additional options, which defaults to: { cwd: undefined, env: process.env, - customFds: [-1, -1, -1] } + customFds: [-1, -1, -1], + setsid: false + } `cwd` allows you to specify the working directory from which the process is spawned. Use `env` to specify environment variables that will be visible to the new process. With `customFds` it is possible to hook up the new process' [stdin, stout, stderr] to -existing streams; `-1` means that a new stream should be created. +existing streams; `-1` means that a new stream should be created. `setsid`, +if set true, will cause the subprocess to be run in a new session. Example of running `ls -lh /usr`, capturing `stdout`, `stderr`, and the exit code: diff --git a/lib/child_process.js b/lib/child_process.js index e179dad689..b594f7a7cf 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -25,6 +25,7 @@ exports.execFile = function(file /* args, options, callback */) { timeout: 0, maxBuffer: 200 * 1024, killSignal: 'SIGTERM', + setsid: false, cwd: null, env: null }; var args, optionArg, callback; @@ -184,7 +185,7 @@ ChildProcess.prototype.kill = function(sig) { ChildProcess.prototype.spawn = function(path, args, options, customFds) { args = args || []; - var cwd, env; + var cwd, env, setuid; if (!options || options.cwd === undefined && options.env === undefined && options.customFds === undefined) { @@ -192,11 +193,13 @@ ChildProcess.prototype.spawn = function(path, args, options, customFds) { cwd = ''; env = options || process.env; customFds = customFds || [-1, -1, -1]; + setuid = false; } else { // Recommended API: (path, args, options) cwd = options.cwd || ''; env = options.env || process.env; customFds = options.customFds || [-1, -1, -1]; + setuid = options.setuid ? true : false; } var envPairs = []; @@ -206,7 +209,12 @@ ChildProcess.prototype.spawn = function(path, args, options, customFds) { envPairs.push(key + '=' + env[key]); } - var fds = this._internal.spawn(path, args, cwd, envPairs, customFds); + var fds = this._internal.spawn(path, + args, + cwd, + envPairs, + customFds, + setuid); this.fds = fds; if (customFds[0] === -1 || customFds[0] === undefined) { diff --git a/src/node_child_process.cc b/src/node_child_process.cc index 87c385708a..eaada0aa45 100644 --- a/src/node_child_process.cc +++ b/src/node_child_process.cc @@ -150,9 +150,15 @@ Handle ChildProcess::Spawn(const Arguments& args) { } } + int do_setuid = false; + if (args[5]->IsBoolean()) { + do_setuid = args[5]->BooleanValue(); + } + + int fds[3]; - int r = child->Spawn(argv[0], argv, cwd, env, fds, custom_fds); + int r = child->Spawn(argv[0], argv, cwd, env, fds, custom_fds, do_setuid); for (i = 0; i < argv_length; i++) free(argv[i]); delete [] argv; @@ -226,7 +232,8 @@ int ChildProcess::Spawn(const char *file, const char *cwd, char **env, int stdio_fds[3], - int custom_fds[3]) { + int custom_fds[3], + bool do_setuid) { HandleScope scope; assert(pid_ == -1); assert(!ev_is_active(&child_watcher_)); @@ -267,6 +274,10 @@ int ChildProcess::Spawn(const char *file, return -4; case 0: // Child. + if (do_setuid && setsid() < 0) { + perror("setuid"); + } + if (custom_fds[0] == -1) { close(stdin_pipe[1]); // close write end dup2(stdin_pipe[0], STDIN_FILENO); diff --git a/src/node_child_process.h b/src/node_child_process.h index 6d78961232..2062a097a9 100644 --- a/src/node_child_process.h +++ b/src/node_child_process.h @@ -58,7 +58,13 @@ class ChildProcess : ObjectWrap { // are readable. // The user of this class has responsibility to close these pipes after // the child process exits. - int Spawn(const char *file, char *const argv[], const char *cwd, char **env, int stdio_fds[3], int custom_fds[3]); + int Spawn(const char *file, + char *const argv[], + const char *cwd, + char **env, + int stdio_fds[3], + int custom_fds[3], + bool do_setuid); // Simple syscall wrapper. Does not disable the watcher. onexit will be // called still.