Child process: support the `gid` and `uid` options
authorBert Belder <bertbelder@gmail.com>
Fri, 27 Apr 2012 20:13:00 +0000 (22:13 +0200)
committerBert Belder <bertbelder@gmail.com>
Fri, 27 Apr 2012 20:13:00 +0000 (22:13 +0200)
lib/child_process.js
src/process_wrap.cc

index d73f65f..f3a5bdd 100644 (file)
@@ -346,7 +346,9 @@ var spawn = exports.spawn = function(file, args, options) {
     windowsVerbatimArguments: !!(options && options.windowsVerbatimArguments),
     envPairs: envPairs,
     customFds: options ? options.customFds : null,
-    stdinStream: options ? options.stdinStream : null
+    stdinStream: options ? options.stdinStream : null,
+    uid: options ? options.uid : null,
+    gid: options ? options.gid : null
   });
 
   return child;
index 6600a04..f9651c4 100644 (file)
@@ -53,6 +53,8 @@ using v8::TryCatch;
 using v8::Context;
 using v8::Arguments;
 using v8::Integer;
+using v8::Exception;
+using v8::ThrowException;
 
 
 class ProcessWrap : public HandleWrap {
@@ -98,7 +100,7 @@ class ProcessWrap : public HandleWrap {
 
     Local<Object> js_options = args[0]->ToObject();
 
-    uv_process_options_t options;
+    uv_process_options2_t options;
     memset(&options, 0, sizeof(uv_process_options_t));
 
     options.exit_cb = OnExit;
@@ -106,14 +108,16 @@ class ProcessWrap : public HandleWrap {
     // TODO is this possible to do without mallocing ?
 
     // options.file
-    Local<Value> file_v = js_options->Get(String::New("file"));
+    Local<Value> file_v = js_options->Get(String::NewSymbol("file"));
     if (!file_v.IsEmpty() && file_v->IsString()) {
       String::Utf8Value file(file_v->ToString());
       options.file = strdup(*file);
+    } else {
+      return ThrowException(Exception::TypeError(String::New("Bad argument")));
     }
 
     // options.args
-    Local<Value> argv_v = js_options->Get(String::New("args"));
+    Local<Value> argv_v = js_options->Get(String::NewSymbol("args"));
     if (!argv_v.IsEmpty() && argv_v->IsArray()) {
       Local<Array> js_argv = Local<Array>::Cast(argv_v);
       int argc = js_argv->Length();
@@ -127,7 +131,7 @@ class ProcessWrap : public HandleWrap {
     }
 
     // options.cwd
-    Local<Value> cwd_v = js_options->Get(String::New("cwd"));
+    Local<Value> cwd_v = js_options->Get(String::NewSymbol("cwd"));
     if (!cwd_v.IsEmpty() && cwd_v->IsString()) {
       String::Utf8Value cwd(cwd_v->ToString());
       if (cwd.length() > 0) {
@@ -136,7 +140,7 @@ class ProcessWrap : public HandleWrap {
     }
 
     // options.env
-    Local<Value> env_v = js_options->Get(String::New("envPairs"));
+    Local<Value> env_v = js_options->Get(String::NewSymbol("envPairs"));
     if (!env_v.IsEmpty() && env_v->IsArray()) {
       Local<Array> env = Local<Array>::Cast(env_v);
       int envc = env->Length();
@@ -149,33 +153,66 @@ class ProcessWrap : public HandleWrap {
     }
 
     // options.stdin_stream
-    Local<Value> stdin_stream_v = js_options->Get(String::New("stdinStream"));
+    Local<Value> stdin_stream_v = js_options->Get(
+        String::NewSymbol("stdinStream"));
     if (!stdin_stream_v.IsEmpty() && stdin_stream_v->IsObject()) {
       PipeWrap* stdin_wrap = PipeWrap::Unwrap(stdin_stream_v->ToObject());
       options.stdin_stream = stdin_wrap->UVHandle();
     }
 
     // options.stdout_stream
-    Local<Value> stdout_stream_v = js_options->Get(String::New("stdoutStream"));
+    Local<Value> stdout_stream_v = js_options->Get(
+        String::NewSymbol("stdoutStream"));
     if (!stdout_stream_v.IsEmpty() && stdout_stream_v->IsObject()) {
       PipeWrap* stdout_wrap = PipeWrap::Unwrap(stdout_stream_v->ToObject());
       options.stdout_stream = stdout_wrap->UVHandle();
     }
 
     // options.stderr_stream
-    Local<Value> stderr_stream_v = js_options->Get(String::New("stderrStream"));
+    Local<Value> stderr_stream_v = js_options->Get(
+        String::NewSymbol("stderrStream"));
     if (!stderr_stream_v.IsEmpty() && stderr_stream_v->IsObject()) {
       PipeWrap* stderr_wrap = PipeWrap::Unwrap(stderr_stream_v->ToObject());
       options.stderr_stream = stderr_wrap->UVHandle();
     }
 
     // options.windows_verbatim_arguments
-#if defined(_WIN32)
-    options.windows_verbatim_arguments = js_options->
-        Get(String::NewSymbol("windowsVerbatimArguments"))->IsTrue();
-#endif
+    if (js_options->Get(String::NewSymbol("windowsVerbatimArguments"))->
+          IsTrue()) {
+      options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
+    }
+
+    // options.uid
+    Local<Value> uid_v = js_options->Get(String::NewSymbol("uid"));
+    if (uid_v->IsInt32()) {
+      int32_t uid = uid_v->Int32Value();
+      if (uid & ~((uv_uid_t) ~0)) {
+        return ThrowException(Exception::RangeError(
+            String::New("options.uid is out of range")));
+      }
+      options.flags |= UV_PROCESS_SETUID;
+      options.uid = (uv_uid_t) uid;
+    } else if (!uid_v->IsUndefined() && !uid_v->IsNull()) {
+      return ThrowException(Exception::TypeError(
+          String::New("options.uid should be a number")));
+    }
+
+    // options.gid
+    Local<Value> gid_v = js_options->Get(String::NewSymbol("gid"));
+    if (gid_v->IsInt32()) {
+      int32_t gid = gid_v->Int32Value();
+      if (gid & ~((uv_gid_t) ~0)) {
+        return ThrowException(Exception::RangeError(
+           String::New("options.gid is out of range")));
+      }
+      options.flags |= UV_PROCESS_SETGID;
+      options.gid = (uv_gid_t) gid;
+    } else if (!gid_v->IsUndefined() && !gid_v->IsNull()) {
+      return ThrowException(Exception::TypeError(
+          String::New("options.gid should be a number")));
+    }
 
-    int r = uv_spawn(uv_default_loop(), &wrap->process_, options);
+    int r = uv_spawn2(uv_default_loop(), &wrap->process_, options);
 
     if (r) {
       SetErrno(uv_last_error(uv_default_loop()));