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