3535#include < sys/wait.h>
3636#endif
3737
38+ #include < sys/socket.h> /* socketpair */
39+ #include < sys/un.h>
40+
3841# ifdef __APPLE__
3942# include < crt_externs.h>
4043# define environ (*_NSGetEnviron ())
@@ -153,7 +156,7 @@ Handle<Value> ChildProcess::Spawn(const Arguments& args) {
153156 // Copy fourth argument, args[3], into a c-string array called env.
154157 Local<Array> env_handle = Local<Array>::Cast (args[3 ]);
155158 int envc = env_handle->Length ();
156- char **env = new char *[envc+ 1 ]; // heap allocated to detect errors
159+ char **env = new char *[envc + 1 ]; // heap allocated to detect errors
157160 env[envc] = NULL ;
158161 for (int i = 0 ; i < envc; i++) {
159162 String::Utf8Value pair (env_handle->Get (Integer::New (i))->ToString ());
@@ -206,7 +209,7 @@ Handle<Value> ChildProcess::Spawn(const Arguments& args) {
206209 String::New (" setgid argument must be a number or a string" )));
207210 }
208211
209-
212+ int channel_fd = - 1 ;
210213
211214 int r = child->Spawn (argv[0 ],
212215 argv,
@@ -218,7 +221,8 @@ Handle<Value> ChildProcess::Spawn(const Arguments& args) {
218221 custom_uid,
219222 custom_uname,
220223 custom_gid,
221- custom_gname);
224+ custom_gname,
225+ &channel_fd);
222226
223227 if (custom_uname != NULL ) free (custom_uname);
224228 if (custom_gname != NULL ) free (custom_gname);
@@ -235,7 +239,8 @@ Handle<Value> ChildProcess::Spawn(const Arguments& args) {
235239 return ThrowException (Exception::Error (String::New (" Error spawning" )));
236240 }
237241
238- Local<Array> a = Array::New (3 );
242+
243+ Local<Array> a = Array::New (channel_fd >= 0 ? 4 : 3 );
239244
240245 assert (fds[0 ] >= 0 );
241246 a->Set (0 , Integer::New (fds[0 ])); // stdin
@@ -244,6 +249,10 @@ Handle<Value> ChildProcess::Spawn(const Arguments& args) {
244249 assert (fds[2 ] >= 0 );
245250 a->Set (2 , Integer::New (fds[2 ])); // stderr
246251
252+ if (channel_fd >= 0 ) {
253+ a->Set (3 , Integer::New (channel_fd));
254+ }
255+
247256 return scope.Close (a);
248257}
249258
@@ -291,6 +300,8 @@ void ChildProcess::Stop() {
291300// Note that args[0] must be the same as the "file" param. This is an
292301// execvp() requirement.
293302//
303+ // TODO: The arguments are rediculously long. Needs to be put into a struct.
304+ //
294305int ChildProcess::Spawn (const char *file,
295306 char *const args[],
296307 const char *cwd,
@@ -301,7 +312,8 @@ int ChildProcess::Spawn(const char *file,
301312 int custom_uid,
302313 char *custom_uname,
303314 int custom_gid,
304- char *custom_gname) {
315+ char *custom_gname,
316+ int * channel) {
305317 HandleScope scope;
306318 assert (pid_ == -1 );
307319 assert (!ev_is_active (&child_watcher_));
@@ -332,11 +344,37 @@ int ChildProcess::Spawn(const char *file,
332344 SetCloseOnExec (stderr_pipe[1 ]);
333345 }
334346
347+
348+ // The channel will be used by spawnNode() for a little JSON channel.
349+ // The pointer is used to pass one end of the socket pair back to the
350+ // parent.
351+ // channel_fds[0] is for the parent
352+ // channel_fds[1] is for the child
353+ int channel_fds[2 ] = { -1 , -1 };
354+
355+ #define NODE_CHANNEL_FD " NODE_CHANNEL_FD"
356+
357+ for (int i = 0 ; env[i]; i++) {
358+ if (!strncmp (env[i], NODE_CHANNEL_FD , sizeof NODE_CHANNEL_FD - 1 )) {
359+ if (socketpair (AF_UNIX , SOCK_STREAM , 0 , channel_fds)) {
360+ perror (" socketpair()" );
361+ return -1 ;
362+ }
363+
364+ assert (channel_fds[0 ] >= 0 && channel_fds[1 ] >= 0 );
365+
366+ SetNonBlocking (channel_fds[0 ]);
367+ SetNonBlocking (channel_fds[1 ]);
368+ // Write over the FILLMEIN :D
369+ sprintf (env[i], NODE_CHANNEL_FD " =%d" , channel_fds[1 ]);
370+ }
371+ }
372+
335373 // Save environ in the case that we get it clobbered
336374 // by the child process.
337375 char **save_our_env = environ;
338376
339- switch (pid_ = vfork ()) {
377+ switch (pid_ = fork ()) {
340378 case -1 : // Error.
341379 Stop ();
342380 return -4 ;
@@ -429,7 +467,11 @@ int ChildProcess::Spawn(const char *file,
429467 _exit (127 );
430468 }
431469
432-
470+ // Close the parent's end of the channel.
471+ if (channel_fds[0 ] >= 0 ) {
472+ close (channel_fds[0 ]);
473+ channel_fds[0 ] = -1 ;
474+ }
433475
434476 environ = env;
435477
@@ -472,6 +514,17 @@ int ChildProcess::Spawn(const char *file,
472514 stdio_fds[2 ] = custom_fds[2 ];
473515 }
474516
517+ // Close the child's end of the channel.
518+ if (channel_fds[1 ] >= 0 ) {
519+ close (channel_fds[1 ]);
520+ channel_fds[1 ] = -1 ;
521+ assert (channel_fds[0 ] >= 0 );
522+ assert (channel);
523+ *channel = channel_fds[0 ];
524+ } else {
525+ *channel = -1 ;
526+ }
527+
475528 return 0 ;
476529}
477530
0 commit comments