src: deduplicate CHECK_EQ/CHECK_NE macros
[platform/upstream/nodejs.git] / src / spawn_sync.cc
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 #include "spawn_sync.h"
23 #include "env-inl.h"
24 #include "string_bytes.h"
25 #include "util.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29
30
31 namespace node {
32
33 using v8::Array;
34 using v8::Context;
35 using v8::EscapableHandleScope;
36 using v8::FunctionCallbackInfo;
37 using v8::Handle;
38 using v8::HandleScope;
39 using v8::Integer;
40 using v8::Isolate;
41 using v8::Local;
42 using v8::Null;
43 using v8::Number;
44 using v8::Object;
45 using v8::String;
46 using v8::Value;
47
48
49 SyncProcessOutputBuffer::SyncProcessOutputBuffer()
50     : used_(0),
51       next_(NULL) {
52 }
53
54
55 void SyncProcessOutputBuffer::OnAlloc(size_t suggested_size,
56                                       uv_buf_t* buf) const {
57   if (used() == kBufferSize)
58     *buf = uv_buf_init(NULL, 0);
59   else
60     *buf = uv_buf_init(data_ + used(), available());
61 }
62
63
64 void SyncProcessOutputBuffer::OnRead(const uv_buf_t* buf, size_t nread) {
65   // If we hand out the same chunk twice, this should catch it.
66   assert(buf->base == data_ + used());
67   used_ += static_cast<unsigned int>(nread);
68 }
69
70
71 size_t SyncProcessOutputBuffer::Copy(char* dest) const {
72   memcpy(dest, data_, used());
73   return used();
74 }
75
76
77 unsigned int SyncProcessOutputBuffer::available() const {
78   return sizeof data_ - used();
79 }
80
81
82 unsigned int SyncProcessOutputBuffer::used() const {
83   return used_;
84 }
85
86
87 SyncProcessOutputBuffer* SyncProcessOutputBuffer::next() const {
88   return next_;
89 }
90
91
92 void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
93   next_ = next;
94 }
95
96
97 SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
98                                            bool readable,
99                                            bool writable,
100                                            uv_buf_t input_buffer)
101     : process_handler_(process_handler),
102       readable_(readable),
103       writable_(writable),
104       input_buffer_(input_buffer),
105
106       first_output_buffer_(NULL),
107       last_output_buffer_(NULL),
108
109       uv_pipe_(),
110       write_req_(),
111       shutdown_req_(),
112
113       lifecycle_(kUninitialized) {
114   assert(readable || writable);
115 }
116
117
118 SyncProcessStdioPipe::~SyncProcessStdioPipe() {
119   assert(lifecycle_ == kUninitialized || lifecycle_ == kClosed);
120
121   SyncProcessOutputBuffer* buf;
122   SyncProcessOutputBuffer* next;
123
124   for (buf = first_output_buffer_; buf != NULL; buf = next) {
125     next = buf->next();
126     delete buf;
127   }
128 }
129
130
131 int SyncProcessStdioPipe::Initialize(uv_loop_t* loop) {
132   assert(lifecycle_ == kUninitialized);
133
134   int r = uv_pipe_init(loop, uv_pipe(), 0);
135   if (r < 0)
136     return r;
137
138   uv_pipe()->data = this;
139
140   lifecycle_ = kInitialized;
141   return 0;
142 }
143
144
145 int SyncProcessStdioPipe::Start() {
146   assert(lifecycle_ == kInitialized);
147
148   // Set the busy flag already. If this function fails no recovery is
149   // possible.
150   lifecycle_ = kStarted;
151
152   if (readable()) {
153     if (input_buffer_.len > 0) {
154       assert(input_buffer_.base != NULL);
155
156       int r = uv_write(&write_req_,
157                        uv_stream(),
158                        &input_buffer_,
159                        1,
160                        WriteCallback);
161       if (r < 0)
162         return r;
163     }
164
165     int r = uv_shutdown(&shutdown_req_, uv_stream(), ShutdownCallback);
166     if (r < 0)
167       return r;
168   }
169
170   if (writable()) {
171     int r = uv_read_start(uv_stream(), AllocCallback, ReadCallback);
172     if (r < 0)
173       return r;
174   }
175
176   return 0;
177 }
178
179
180 void SyncProcessStdioPipe::Close() {
181   assert(lifecycle_ == kInitialized || lifecycle_ == kStarted);
182
183   uv_close(uv_handle(), CloseCallback);
184
185   lifecycle_ = kClosing;
186 }
187
188
189 Local<Object> SyncProcessStdioPipe::GetOutputAsBuffer() const {
190   size_t length = OutputLength();
191   Local<Object> js_buffer = Buffer::New(length);
192   CopyOutput(Buffer::Data(js_buffer));
193   return js_buffer;
194 }
195
196
197 bool SyncProcessStdioPipe::readable() const {
198   return readable_;
199 }
200
201
202 bool SyncProcessStdioPipe::writable() const {
203   return writable_;
204 }
205
206
207 uv_stdio_flags SyncProcessStdioPipe::uv_flags() const {
208   unsigned int flags;
209
210   flags = UV_CREATE_PIPE;
211   if (readable())
212     flags |= UV_READABLE_PIPE;
213   if (writable())
214     flags |= UV_WRITABLE_PIPE;
215
216   return static_cast<uv_stdio_flags>(flags);
217 }
218
219
220 uv_pipe_t* SyncProcessStdioPipe::uv_pipe() const {
221   assert(lifecycle_ < kClosing);
222   return &uv_pipe_;
223 }
224
225
226 uv_stream_t* SyncProcessStdioPipe::uv_stream() const {
227   return reinterpret_cast<uv_stream_t*>(uv_pipe());
228 }
229
230
231 uv_handle_t* SyncProcessStdioPipe::uv_handle() const {
232   return reinterpret_cast<uv_handle_t*>(uv_pipe());
233 }
234
235
236 size_t SyncProcessStdioPipe::OutputLength() const {
237   SyncProcessOutputBuffer* buf;
238   size_t size = 0;
239
240   for (buf = first_output_buffer_; buf != NULL; buf = buf->next())
241     size += buf->used();
242
243   return size;
244 }
245
246
247 void SyncProcessStdioPipe::CopyOutput(char* dest) const {
248   SyncProcessOutputBuffer* buf;
249   size_t offset = 0;
250
251   for (buf = first_output_buffer_; buf != NULL; buf = buf->next())
252     offset += buf->Copy(dest + offset);
253 }
254
255
256 void SyncProcessStdioPipe::OnAlloc(size_t suggested_size, uv_buf_t* buf) {
257   // This function assumes that libuv will never allocate two buffers for the
258   // same stream at the same time. There's an assert in
259   // SyncProcessOutputBuffer::OnRead that would fail if this assumption was
260   // ever violated.
261
262   if (last_output_buffer_ == NULL) {
263     // Allocate the first capture buffer.
264     first_output_buffer_ = new SyncProcessOutputBuffer();
265     last_output_buffer_ = first_output_buffer_;
266
267   } else if (last_output_buffer_->available() == 0) {
268     // The current capture buffer is full so get us a new one.
269     SyncProcessOutputBuffer* buf = new SyncProcessOutputBuffer();
270     last_output_buffer_->set_next(buf);
271     last_output_buffer_ = buf;
272   }
273
274   last_output_buffer_->OnAlloc(suggested_size, buf);
275 }
276
277
278 void SyncProcessStdioPipe::OnRead(const uv_buf_t* buf, ssize_t nread) {
279   if (nread == UV_EOF) {
280     // Libuv implicitly stops reading on EOF.
281
282   } else if (nread < 0) {
283     SetError(static_cast<int>(nread));
284     // At some point libuv should really implicitly stop reading on error.
285     uv_read_stop(uv_stream());
286
287   } else {
288     last_output_buffer_->OnRead(buf, nread);
289     process_handler_->IncrementBufferSizeAndCheckOverflow(nread);
290   }
291 }
292
293
294 void SyncProcessStdioPipe::OnWriteDone(int result) {
295   if (result < 0)
296     SetError(result);
297 }
298
299
300 void SyncProcessStdioPipe::OnShutdownDone(int result) {
301   if (result < 0)
302     SetError(result);
303 }
304
305
306 void SyncProcessStdioPipe::OnClose() {
307   lifecycle_ = kClosed;
308 }
309
310
311 void SyncProcessStdioPipe::SetError(int error) {
312   assert(error != 0);
313   process_handler_->SetPipeError(error);
314 }
315
316
317 void SyncProcessStdioPipe::AllocCallback(uv_handle_t* handle,
318                                          size_t suggested_size,
319                                          uv_buf_t* buf) {
320   SyncProcessStdioPipe* self =
321       reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
322   self->OnAlloc(suggested_size, buf);
323 }
324
325
326 void SyncProcessStdioPipe::ReadCallback(uv_stream_t* stream,
327                                         ssize_t nread,
328                                         const uv_buf_t* buf) {
329   SyncProcessStdioPipe* self =
330         reinterpret_cast<SyncProcessStdioPipe*>(stream->data);
331   self->OnRead(buf, nread);
332 }
333
334
335 void SyncProcessStdioPipe::WriteCallback(uv_write_t* req, int result) {
336   SyncProcessStdioPipe* self =
337       reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
338   self->OnWriteDone(result);
339 }
340
341
342 void SyncProcessStdioPipe::ShutdownCallback(uv_shutdown_t* req, int result) {
343   SyncProcessStdioPipe* self =
344       reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
345   self->OnShutdownDone(result);
346 }
347
348
349 void SyncProcessStdioPipe::CloseCallback(uv_handle_t* handle) {
350   SyncProcessStdioPipe* self =
351       reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
352   self->OnClose();
353 }
354
355
356 void SyncProcessRunner::Initialize(Handle<Object> target,
357                                    Handle<Value> unused,
358                                    Handle<Context> context) {
359   NODE_SET_METHOD(target, "spawn", Spawn);
360 }
361
362
363 void SyncProcessRunner::Spawn(const FunctionCallbackInfo<Value>& args) {
364   Isolate* isolate = args.GetIsolate();
365   HandleScope scope(isolate);
366   SyncProcessRunner p(Environment::GetCurrent(isolate));
367   Local<Value> result = p.Run(args[0]);
368   args.GetReturnValue().Set(result);
369 }
370
371
372 SyncProcessRunner::SyncProcessRunner(Environment* env)
373     : max_buffer_(0),
374       timeout_(0),
375       kill_signal_(SIGTERM),
376
377       uv_loop_(NULL),
378
379       stdio_count_(0),
380       uv_stdio_containers_(NULL),
381       stdio_pipes_(NULL),
382       stdio_pipes_initialized_(false),
383
384       uv_process_options_(),
385       file_buffer_(NULL),
386       args_buffer_(NULL),
387       env_buffer_(NULL),
388       cwd_buffer_(NULL),
389
390       uv_process_(),
391       killed_(false),
392
393       buffered_output_size_(0),
394       exit_status_(-1),
395       term_signal_(-1),
396
397       uv_timer_(),
398       kill_timer_initialized_(false),
399
400       error_(0),
401       pipe_error_(0),
402
403       lifecycle_(kUninitialized),
404
405       env_(env) {
406 }
407
408
409 SyncProcessRunner::~SyncProcessRunner() {
410   assert(lifecycle_ == kHandlesClosed);
411
412   if (stdio_pipes_ != NULL) {
413     for (size_t i = 0; i < stdio_count_; i++) {
414       if (stdio_pipes_[i] != NULL)
415         delete stdio_pipes_[i];
416     }
417   }
418
419   delete[] stdio_pipes_;
420   delete[] file_buffer_;
421   delete[] args_buffer_;
422   delete[] cwd_buffer_;
423   delete[] env_buffer_;
424   delete[] uv_stdio_containers_;
425 }
426
427
428 Environment* SyncProcessRunner::env() const {
429   return env_;
430 }
431
432
433 Local<Object> SyncProcessRunner::Run(Local<Value> options) {
434   EscapableHandleScope scope(env()->isolate());
435
436   assert(lifecycle_ == kUninitialized);
437
438   TryInitializeAndRunLoop(options);
439   CloseHandlesAndDeleteLoop();
440
441   Local<Object> result = BuildResultObject();
442
443   return scope.Escape(result);
444 }
445
446
447 void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
448   int r;
449
450   // There is no recovery from failure inside TryInitializeAndRunLoop - the
451   // only option we'd have is to close all handles and destroy the loop.
452   assert(lifecycle_ == kUninitialized);
453   lifecycle_ = kInitialized;
454
455   uv_loop_ = new uv_loop_t;
456   if (uv_loop_ == NULL)
457     return SetError(UV_ENOMEM);
458   CHECK_EQ(uv_loop_init(uv_loop_), 0);
459
460   r = ParseOptions(options);
461   if (r < 0)
462     return SetError(r);
463
464   if (timeout_ > 0) {
465     r = uv_timer_init(uv_loop_, &uv_timer_);
466     if (r < 0)
467       return SetError(r);
468
469     uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
470
471     uv_timer_.data = this;
472     kill_timer_initialized_ = true;
473
474     // Start the timer immediately. If uv_spawn fails then
475     // CloseHandlesAndDeleteLoop() will immediately close the timer handle
476     // which implicitly stops it, so there is no risk that the timeout callback
477     // runs when the process didn't start.
478     r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
479     if (r < 0)
480       return SetError(r);
481   }
482
483   uv_process_options_.exit_cb = ExitCallback;
484   r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
485   if (r < 0)
486     return SetError(r);
487   uv_process_.data = this;
488
489   for (uint32_t i = 0; i < stdio_count_; i++) {
490     SyncProcessStdioPipe* h = stdio_pipes_[i];
491     if (h != NULL) {
492       r = h->Start();
493       if (r < 0)
494         return SetPipeError(r);
495     }
496   }
497
498   r = uv_run(uv_loop_, UV_RUN_DEFAULT);
499   if (r < 0)
500     // We can't handle uv_run failure.
501     abort();
502
503   // If we get here the process should have exited.
504   assert(exit_status_ >= 0);
505 }
506
507
508 void SyncProcessRunner::CloseHandlesAndDeleteLoop() {
509   assert(lifecycle_ < kHandlesClosed);
510
511   if (uv_loop_ != NULL) {
512     CloseStdioPipes();
513     CloseKillTimer();
514
515     // Give closing watchers a chance to finish closing and get their close
516     // callbacks called.
517     int r = uv_run(uv_loop_, UV_RUN_DEFAULT);
518     if (r < 0)
519       abort();
520
521     CHECK_EQ(uv_loop_close(uv_loop_), 0);
522     delete uv_loop_;
523     uv_loop_ = NULL;
524
525   } else {
526     // If the loop doesn't exist, neither should any pipes or timers.
527     assert(!stdio_pipes_initialized_);
528     assert(!kill_timer_initialized_);
529   }
530
531   lifecycle_ = kHandlesClosed;
532 }
533
534
535 void SyncProcessRunner::CloseStdioPipes() {
536   assert(lifecycle_ < kHandlesClosed);
537
538   if (stdio_pipes_initialized_) {
539     assert(stdio_pipes_ != NULL);
540     assert(uv_loop_ != NULL);
541
542     for (uint32_t i = 0; i < stdio_count_; i++) {
543       if (stdio_pipes_[i] != NULL)
544         stdio_pipes_[i]->Close();
545     }
546
547     stdio_pipes_initialized_ = false;
548   }
549 }
550
551
552 void SyncProcessRunner::CloseKillTimer() {
553   assert(lifecycle_ < kHandlesClosed);
554
555   if (kill_timer_initialized_) {
556     assert(timeout_ > 0);
557     assert(uv_loop_ != NULL);
558
559     uv_handle_t* uv_timer_handle = reinterpret_cast<uv_handle_t*>(&uv_timer_);
560     uv_ref(uv_timer_handle);
561     uv_close(uv_timer_handle, KillTimerCloseCallback);
562
563     kill_timer_initialized_ = false;
564   }
565 }
566
567
568 void SyncProcessRunner::Kill() {
569   // Only attempt to kill once.
570   if (killed_)
571     return;
572   killed_ = true;
573
574   // We might get here even if the process we spawned has already exited. This
575   // could happen when our child process spawned another process which
576   // inherited (one of) the stdio pipes. In this case we won't attempt to send
577   // a signal to the process, however we will still close our end of the stdio
578   // pipes so this situation won't make us hang.
579   if (exit_status_ < 0) {
580     int r = uv_process_kill(&uv_process_, kill_signal_);
581
582     // If uv_kill failed with an error that isn't ESRCH, the user probably
583     // specified an invalid or unsupported signal. Signal this to the user as
584     // and error and kill the process with SIGKILL instead.
585     if (r < 0 && r != UV_ESRCH) {
586       SetError(r);
587
588       r = uv_process_kill(&uv_process_, SIGKILL);
589       assert(r >= 0 || r == UV_ESRCH);
590     }
591   }
592
593   // Close all stdio pipes.
594   CloseStdioPipes();
595
596   // Stop the timeout timer immediately.
597   CloseKillTimer();
598 }
599
600
601 void SyncProcessRunner::IncrementBufferSizeAndCheckOverflow(ssize_t length) {
602   buffered_output_size_ += length;
603
604   if (max_buffer_ > 0 && buffered_output_size_ > max_buffer_) {
605     SetError(UV_ENOBUFS);
606     Kill();
607   }
608 }
609
610
611 void SyncProcessRunner::OnExit(int64_t exit_status, int term_signal) {
612   if (exit_status < 0)
613     return SetError(static_cast<int>(exit_status));
614
615   exit_status_ = exit_status;
616   term_signal_ = term_signal;
617 }
618
619
620 void SyncProcessRunner::OnKillTimerTimeout(int status) {
621   assert(status == 0);
622   SetError(UV_ETIMEDOUT);
623   Kill();
624 }
625
626
627 int SyncProcessRunner::GetError() {
628   if (error_ != 0)
629     return error_;
630   else
631     return pipe_error_;
632 }
633
634
635 void SyncProcessRunner::SetError(int error) {
636   if (error_ == 0)
637     error_ = error;
638 }
639
640
641 void SyncProcessRunner::SetPipeError(int pipe_error) {
642   if (pipe_error_ == 0)
643     pipe_error_ = pipe_error;
644 }
645
646
647 Local<Object> SyncProcessRunner::BuildResultObject() {
648   EscapableHandleScope scope(env()->isolate());
649
650   Local<Object> js_result = Object::New(env()->isolate());
651
652   if (GetError() != 0) {
653     js_result->Set(env()->error_string(),
654                    Integer::New(env()->isolate(), GetError()));
655   }
656
657   if (exit_status_ >= 0)
658     js_result->Set(env()->status_string(),
659         Number::New(env()->isolate(), static_cast<double>(exit_status_)));
660   else
661     // If exit_status_ < 0 the process was never started because of some error.
662     js_result->Set(env()->status_string(), Null(env()->isolate()));
663
664   if (term_signal_ > 0)
665     js_result->Set(env()->signal_string(),
666         String::NewFromUtf8(env()->isolate(), signo_string(term_signal_)));
667   else
668     js_result->Set(env()->signal_string(), Null(env()->isolate()));
669
670   if (exit_status_ >= 0)
671     js_result->Set(env()->output_string(), BuildOutputArray());
672   else
673     js_result->Set(env()->output_string(), Null(env()->isolate()));
674
675   js_result->Set(env()->pid_string(),
676                  Number::New(env()->isolate(), uv_process_.pid));
677
678   return scope.Escape(js_result);
679 }
680
681
682 Local<Array> SyncProcessRunner::BuildOutputArray() {
683   assert(lifecycle_ >= kInitialized);
684   assert(stdio_pipes_ != NULL);
685
686   EscapableHandleScope scope(env()->isolate());
687   Local<Array> js_output = Array::New(env()->isolate(), stdio_count_);
688
689   for (uint32_t i = 0; i < stdio_count_; i++) {
690     SyncProcessStdioPipe* h = stdio_pipes_[i];
691     if (h != NULL && h->writable())
692       js_output->Set(i, h->GetOutputAsBuffer());
693     else
694       js_output->Set(i, Null(env()->isolate()));
695   }
696
697   return scope.Escape(js_output);
698 }
699
700
701 int SyncProcessRunner::ParseOptions(Local<Value> js_value) {
702   HandleScope scope(env()->isolate());
703   int r;
704
705   if (!js_value->IsObject())
706     return UV_EINVAL;
707
708   Local<Object> js_options = js_value.As<Object>();
709
710   Local<Value> js_file = js_options->Get(env()->file_string());
711   r = CopyJsString(js_file, &file_buffer_);
712   if (r < 0)
713     return r;
714   uv_process_options_.file = file_buffer_;
715
716   Local<Value> js_args = js_options->Get(env()->args_string());
717   r = CopyJsStringArray(js_args, &args_buffer_);
718   if (r < 0)
719     return r;
720   uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);
721
722
723   Local<Value> js_cwd = js_options->Get(env()->cwd_string());
724   if (IsSet(js_cwd)) {
725     r = CopyJsString(js_cwd, &uv_process_options_.cwd);
726     if (r < 0)
727       return r;
728     uv_process_options_.cwd = cwd_buffer_;
729   }
730
731   Local<Value> js_env_pairs = js_options->Get(env()->env_pairs_string());
732   if (IsSet(js_env_pairs)) {
733     r = CopyJsStringArray(js_env_pairs, &env_buffer_);
734     if (r < 0)
735       return r;
736     uv_process_options_.args = reinterpret_cast<char**>(env_buffer_);
737   }
738
739   Local<Value> js_uid = js_options->Get(env()->uid_string());
740   if (IsSet(js_uid)) {
741     if (!CheckRange<uv_uid_t>(js_uid))
742       return UV_EINVAL;
743     uv_process_options_.uid = static_cast<uv_gid_t>(js_uid->Int32Value());
744     uv_process_options_.flags |= UV_PROCESS_SETUID;
745   }
746
747   Local<Value> js_gid = js_options->Get(env()->gid_string());
748   if (IsSet(js_gid)) {
749     if (!CheckRange<uv_gid_t>(js_gid))
750       return UV_EINVAL;
751     uv_process_options_.gid = static_cast<uv_gid_t>(js_gid->Int32Value());
752     uv_process_options_.flags |= UV_PROCESS_SETGID;
753   }
754
755   if (js_options->Get(env()->detached_string())->BooleanValue())
756     uv_process_options_.flags |= UV_PROCESS_DETACHED;
757
758   Local<String> wba = env()->windows_verbatim_arguments_string();
759
760   if (js_options->Get(wba)->BooleanValue())
761     uv_process_options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
762
763   Local<Value> js_timeout = js_options->Get(env()->timeout_string());
764   if (IsSet(js_timeout)) {
765     if (!js_timeout->IsNumber())
766       return UV_EINVAL;
767     int64_t timeout = js_timeout->IntegerValue();
768     if (timeout < 0)
769       return UV_EINVAL;
770     timeout_ = static_cast<uint64_t>(timeout);
771   }
772
773   Local<Value> js_max_buffer = js_options->Get(env()->max_buffer_string());
774   if (IsSet(js_max_buffer)) {
775     if (!CheckRange<uint32_t>(js_max_buffer))
776       return UV_EINVAL;
777     max_buffer_ = js_max_buffer->Uint32Value();
778   }
779
780   Local<Value> js_kill_signal = js_options->Get(env()->kill_signal_string());
781   if (IsSet(js_kill_signal)) {
782     if (!js_kill_signal->IsInt32())
783       return UV_EINVAL;
784     kill_signal_ = js_kill_signal->Int32Value();
785     if (kill_signal_ == 0)
786       return UV_EINVAL;
787   }
788
789   Local<Value> js_stdio = js_options->Get(env()->stdio_string());
790   r = ParseStdioOptions(js_stdio);
791   if (r < 0)
792     return r;
793
794   return 0;
795 }
796
797
798 int SyncProcessRunner::ParseStdioOptions(Local<Value> js_value) {
799   HandleScope scope(env()->isolate());
800   Local<Array> js_stdio_options;
801
802   if (!js_value->IsArray())
803     return UV_EINVAL;
804
805   js_stdio_options = js_value.As<Array>();
806
807   stdio_count_ = js_stdio_options->Length();
808   uv_stdio_containers_ = new uv_stdio_container_t[stdio_count_];
809
810   stdio_pipes_ = new SyncProcessStdioPipe*[stdio_count_]();
811   stdio_pipes_initialized_ = true;
812
813   for (uint32_t i = 0; i < stdio_count_; i++) {
814     Local<Value> js_stdio_option = js_stdio_options->Get(i);
815
816     if (!js_stdio_option->IsObject())
817       return UV_EINVAL;
818
819     int r = ParseStdioOption(i, js_stdio_option.As<Object>());
820     if (r < 0)
821       return r;
822   }
823
824   uv_process_options_.stdio = uv_stdio_containers_;
825   uv_process_options_.stdio_count = stdio_count_;
826
827   return 0;
828 }
829
830
831 int SyncProcessRunner::ParseStdioOption(int child_fd,
832                                         Local<Object> js_stdio_option) {
833   Local<Value> js_type = js_stdio_option->Get(env()->type_string());
834
835   if (js_type->StrictEquals(env()->ignore_string())) {
836     return AddStdioIgnore(child_fd);
837
838   } else if (js_type->StrictEquals(env()->pipe_string())) {
839     Local<String> rs = env()->readable_string();
840     Local<String> ws = env()->writable_string();
841
842     bool readable = js_stdio_option->Get(rs)->BooleanValue();
843     bool writable = js_stdio_option->Get(ws)->BooleanValue();
844
845     uv_buf_t buf = uv_buf_init(NULL, 0);
846
847     if (readable) {
848       Local<Value> input = js_stdio_option->Get(env()->input_string());
849       if (Buffer::HasInstance(input)) {
850         buf = uv_buf_init(Buffer::Data(input),
851                           static_cast<unsigned int>(Buffer::Length(input)));
852       } else if (!input->IsUndefined() && !input->IsNull()) {
853         // Strings, numbers etc. are currently unsupported. It's not possible
854         // to create a buffer for them here because there is no way to free
855         // them afterwards.
856         return UV_EINVAL;
857       }
858     }
859
860     return AddStdioPipe(child_fd, readable, writable, buf);
861
862   } else if (js_type->StrictEquals(env()->inherit_string()) ||
863              js_type->StrictEquals(env()->fd_string())) {
864     int inherit_fd = js_stdio_option->Get(env()->fd_string())->Int32Value();
865     return AddStdioInheritFD(child_fd, inherit_fd);
866
867   } else {
868     assert(0 && "invalid child stdio type");
869     return UV_EINVAL;
870   }
871 }
872
873
874 int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) {
875   assert(child_fd < stdio_count_);
876   assert(stdio_pipes_[child_fd] == NULL);
877
878   uv_stdio_containers_[child_fd].flags = UV_IGNORE;
879
880   return 0;
881 }
882
883
884 int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
885                                     bool readable,
886                                     bool writable,
887                                     uv_buf_t input_buffer) {
888   assert(child_fd < stdio_count_);
889   assert(stdio_pipes_[child_fd] == NULL);
890
891   SyncProcessStdioPipe* h = new SyncProcessStdioPipe(this,
892                                                      readable,
893                                                      writable,
894                                                      input_buffer);
895
896   int r = h->Initialize(uv_loop_);
897   if (r < 0) {
898     delete h;
899     return r;
900   }
901
902   stdio_pipes_[child_fd] = h;
903
904   uv_stdio_containers_[child_fd].flags = h->uv_flags();
905   uv_stdio_containers_[child_fd].data.stream = h->uv_stream();
906
907   return 0;
908 }
909
910
911 int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) {
912   assert(child_fd < stdio_count_);
913   assert(stdio_pipes_[child_fd] == NULL);
914
915   uv_stdio_containers_[child_fd].flags = UV_INHERIT_FD;
916   uv_stdio_containers_[child_fd].data.fd = inherit_fd;
917
918   return 0;
919 }
920
921
922 bool SyncProcessRunner::IsSet(Local<Value> value) {
923   return !value->IsUndefined() && !value->IsNull();
924 }
925
926
927 template <typename t>
928 bool SyncProcessRunner::CheckRange(Local<Value> js_value) {
929   if ((t) -1 > 0) {
930     // Unsigned range check.
931     if (!js_value->IsUint32())
932       return false;
933     if (js_value->Uint32Value() & ~((t) ~0))
934       return false;
935
936   } else {
937     // Signed range check.
938     if (!js_value->IsInt32())
939       return false;
940     if (js_value->Int32Value() & ~((t) ~0))
941       return false;
942   }
943
944   return true;
945 }
946
947
948 int SyncProcessRunner::CopyJsString(Local<Value> js_value,
949                                     const char** target) {
950   Isolate* isolate = env()->isolate();
951   Local<String> js_string;
952   size_t size, written;
953   char* buffer;
954
955   if (js_value->IsString())
956     js_string = js_value.As<String>();
957   else
958     js_string = js_value->ToString();
959
960   // Include space for null terminator byte.
961   size = StringBytes::StorageSize(isolate, js_string, UTF8) + 1;
962
963   buffer = new char[size];
964
965   written = StringBytes::Write(isolate, buffer, -1, js_string, UTF8);
966   buffer[written] = '\0';
967
968   *target = buffer;
969   return 0;
970 }
971
972
973 int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
974                                          char** target) {
975   Isolate* isolate = env()->isolate();
976   Local<Array> js_array;
977   uint32_t length;
978   size_t list_size, data_size, data_offset;
979   char** list;
980   char* buffer;
981
982   if (!js_value->IsArray())
983     return UV_EINVAL;
984
985   js_array = js_value.As<Array>()->Clone().As<Array>();
986   length = js_array->Length();
987
988   // Convert all array elements to string. Modify the js object itself if
989   // needed - it's okay since we cloned the original object.
990   for (uint32_t i = 0; i < length; i++) {
991     if (!js_array->Get(i)->IsString())
992       js_array->Set(i, js_array->Get(i)->ToString());
993   }
994
995   // Index has a pointer to every string element, plus one more for a final
996   // null pointer.
997   list_size = (length + 1) * sizeof *list;
998
999   // Compute the length of all strings. Include room for null terminator
1000   // after every string. Align strings to cache lines.
1001   data_size = 0;
1002   for (uint32_t i = 0; i < length; i++) {
1003     data_size += StringBytes::StorageSize(isolate, js_array->Get(i), UTF8) + 1;
1004     data_size = ROUND_UP(data_size, sizeof(void*));  // NOLINT(runtime/sizeof)
1005   }
1006
1007   buffer = new char[list_size + data_size];
1008
1009   list = reinterpret_cast<char**>(buffer);
1010   data_offset = list_size;
1011
1012   for (uint32_t i = 0; i < length; i++) {
1013     list[i] = buffer + data_offset;
1014     data_offset += StringBytes::Write(isolate,
1015                                       buffer + data_offset,
1016                                       -1,
1017                                       js_array->Get(i),
1018                                       UTF8);
1019     buffer[data_offset++] = '\0';
1020     data_offset = ROUND_UP(data_offset,
1021                            sizeof(void*));  // NOLINT(runtime/sizeof)
1022   }
1023
1024   list[length] = NULL;
1025
1026   *target = buffer;
1027   return 0;
1028 }
1029
1030
1031 void SyncProcessRunner::ExitCallback(uv_process_t* handle,
1032                                      int64_t exit_status,
1033                                      int term_signal) {
1034   SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1035   uv_close(reinterpret_cast<uv_handle_t*>(handle), NULL);
1036   self->OnExit(exit_status, term_signal);
1037 }
1038
1039
1040 void SyncProcessRunner::KillTimerCallback(uv_timer_t* handle, int status) {
1041   SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1042   self->OnKillTimerTimeout(status);
1043 }
1044
1045
1046 void SyncProcessRunner::KillTimerCloseCallback(uv_handle_t* handle) {
1047   // No-op.
1048 }
1049
1050 }  // namespace node
1051
1052 NODE_MODULE_CONTEXT_AWARE_BUILTIN(spawn_sync,
1053   node::SyncProcessRunner::Initialize)