xref: /third_party/node/deps/v8/src/d8/d8-posix.cc (revision 1cb0ef41)
11cb0ef41Sopenharmony_ci// Copyright 2009 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include <errno.h>
61cb0ef41Sopenharmony_ci#include <fcntl.h>
71cb0ef41Sopenharmony_ci#include <netinet/ip.h>
81cb0ef41Sopenharmony_ci#include <signal.h>
91cb0ef41Sopenharmony_ci#include <stdlib.h>
101cb0ef41Sopenharmony_ci#include <string.h>
111cb0ef41Sopenharmony_ci#include <sys/select.h>
121cb0ef41Sopenharmony_ci#include <sys/socket.h>
131cb0ef41Sopenharmony_ci#include <sys/stat.h>
141cb0ef41Sopenharmony_ci#include <sys/time.h>
151cb0ef41Sopenharmony_ci#include <sys/types.h>
161cb0ef41Sopenharmony_ci#include <sys/wait.h>
171cb0ef41Sopenharmony_ci#include <unistd.h>
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci#include "include/v8-container.h"
201cb0ef41Sopenharmony_ci#include "include/v8-template.h"
211cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h"
221cb0ef41Sopenharmony_ci#include "src/d8/d8.h"
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_cinamespace v8 {
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci// If the buffer ends in the middle of a UTF-8 sequence then we return
271cb0ef41Sopenharmony_ci// the length of the string up to but not including the incomplete UTF-8
281cb0ef41Sopenharmony_ci// sequence.  If the buffer ends with a valid UTF-8 sequence then we
291cb0ef41Sopenharmony_ci// return the whole buffer.
301cb0ef41Sopenharmony_cistatic int LengthWithoutIncompleteUtf8(char* buffer, int len) {
311cb0ef41Sopenharmony_ci  int answer = len;
321cb0ef41Sopenharmony_ci  // 1-byte encoding.
331cb0ef41Sopenharmony_ci  static const int kUtf8SingleByteMask = 0x80;
341cb0ef41Sopenharmony_ci  static const int kUtf8SingleByteValue = 0x00;
351cb0ef41Sopenharmony_ci  // 2-byte encoding.
361cb0ef41Sopenharmony_ci  static const int kUtf8TwoByteMask = 0xE0;
371cb0ef41Sopenharmony_ci  static const int kUtf8TwoByteValue = 0xC0;
381cb0ef41Sopenharmony_ci  // 3-byte encoding.
391cb0ef41Sopenharmony_ci  static const int kUtf8ThreeByteMask = 0xF0;
401cb0ef41Sopenharmony_ci  static const int kUtf8ThreeByteValue = 0xE0;
411cb0ef41Sopenharmony_ci  // 4-byte encoding.
421cb0ef41Sopenharmony_ci  static const int kUtf8FourByteMask = 0xF8;
431cb0ef41Sopenharmony_ci  static const int kUtf8FourByteValue = 0xF0;
441cb0ef41Sopenharmony_ci  // Subsequent bytes of a multi-byte encoding.
451cb0ef41Sopenharmony_ci  static const int kMultiByteMask = 0xC0;
461cb0ef41Sopenharmony_ci  static const int kMultiByteValue = 0x80;
471cb0ef41Sopenharmony_ci  int multi_byte_bytes_seen = 0;
481cb0ef41Sopenharmony_ci  while (answer > 0) {
491cb0ef41Sopenharmony_ci    int c = buffer[answer - 1];
501cb0ef41Sopenharmony_ci    // Ends in valid single-byte sequence?
511cb0ef41Sopenharmony_ci    if ((c & kUtf8SingleByteMask) == kUtf8SingleByteValue) return answer;
521cb0ef41Sopenharmony_ci    // Ends in one or more subsequent bytes of a multi-byte value?
531cb0ef41Sopenharmony_ci    if ((c & kMultiByteMask) == kMultiByteValue) {
541cb0ef41Sopenharmony_ci      multi_byte_bytes_seen++;
551cb0ef41Sopenharmony_ci      answer--;
561cb0ef41Sopenharmony_ci    } else {
571cb0ef41Sopenharmony_ci      if ((c & kUtf8TwoByteMask) == kUtf8TwoByteValue) {
581cb0ef41Sopenharmony_ci        if (multi_byte_bytes_seen >= 1) {
591cb0ef41Sopenharmony_ci          return answer + 2;
601cb0ef41Sopenharmony_ci        }
611cb0ef41Sopenharmony_ci        return answer - 1;
621cb0ef41Sopenharmony_ci      } else if ((c & kUtf8ThreeByteMask) == kUtf8ThreeByteValue) {
631cb0ef41Sopenharmony_ci        if (multi_byte_bytes_seen >= 2) {
641cb0ef41Sopenharmony_ci          return answer + 3;
651cb0ef41Sopenharmony_ci        }
661cb0ef41Sopenharmony_ci        return answer - 1;
671cb0ef41Sopenharmony_ci      } else if ((c & kUtf8FourByteMask) == kUtf8FourByteValue) {
681cb0ef41Sopenharmony_ci        if (multi_byte_bytes_seen >= 3) {
691cb0ef41Sopenharmony_ci          return answer + 4;
701cb0ef41Sopenharmony_ci        }
711cb0ef41Sopenharmony_ci        return answer - 1;
721cb0ef41Sopenharmony_ci      } else {
731cb0ef41Sopenharmony_ci        return answer;  // Malformed UTF-8.
741cb0ef41Sopenharmony_ci      }
751cb0ef41Sopenharmony_ci    }
761cb0ef41Sopenharmony_ci  }
771cb0ef41Sopenharmony_ci  return 0;
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci// Suspends the thread until there is data available from the child process.
811cb0ef41Sopenharmony_ci// Returns false on timeout, true on data ready.
821cb0ef41Sopenharmony_cistatic bool WaitOnFD(int fd, int read_timeout, int total_timeout,
831cb0ef41Sopenharmony_ci                     const struct timeval& start_time) {
841cb0ef41Sopenharmony_ci  fd_set readfds, writefds, exceptfds;
851cb0ef41Sopenharmony_ci  struct timeval timeout;
861cb0ef41Sopenharmony_ci  int gone = 0;
871cb0ef41Sopenharmony_ci  if (total_timeout != -1) {
881cb0ef41Sopenharmony_ci    struct timeval time_now;
891cb0ef41Sopenharmony_ci    gettimeofday(&time_now, nullptr);
901cb0ef41Sopenharmony_ci    time_t seconds = time_now.tv_sec - start_time.tv_sec;
911cb0ef41Sopenharmony_ci    gone = static_cast<int>(seconds * 1000 +
921cb0ef41Sopenharmony_ci                            (time_now.tv_usec - start_time.tv_usec) / 1000);
931cb0ef41Sopenharmony_ci    if (gone >= total_timeout) return false;
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci  FD_ZERO(&readfds);
961cb0ef41Sopenharmony_ci  FD_ZERO(&writefds);
971cb0ef41Sopenharmony_ci  FD_ZERO(&exceptfds);
981cb0ef41Sopenharmony_ci  FD_SET(fd, &readfds);
991cb0ef41Sopenharmony_ci  FD_SET(fd, &exceptfds);
1001cb0ef41Sopenharmony_ci  if (read_timeout == -1 ||
1011cb0ef41Sopenharmony_ci      (total_timeout != -1 && total_timeout - gone < read_timeout)) {
1021cb0ef41Sopenharmony_ci    read_timeout = total_timeout - gone;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci  timeout.tv_usec = (read_timeout % 1000) * 1000;
1051cb0ef41Sopenharmony_ci  timeout.tv_sec = read_timeout / 1000;
1061cb0ef41Sopenharmony_ci  int number_of_fds_ready = select(fd + 1, &readfds, &writefds, &exceptfds,
1071cb0ef41Sopenharmony_ci                                   read_timeout != -1 ? &timeout : nullptr);
1081cb0ef41Sopenharmony_ci  return number_of_fds_ready == 1;
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci// Checks whether we ran out of time on the timeout.  Returns true if we ran out
1121cb0ef41Sopenharmony_ci// of time, false if we still have time.
1131cb0ef41Sopenharmony_cistatic bool TimeIsOut(const struct timeval& start_time, const int& total_time) {
1141cb0ef41Sopenharmony_ci  if (total_time == -1) return false;
1151cb0ef41Sopenharmony_ci  struct timeval time_now;
1161cb0ef41Sopenharmony_ci  gettimeofday(&time_now, nullptr);
1171cb0ef41Sopenharmony_ci  // Careful about overflow.
1181cb0ef41Sopenharmony_ci  int seconds = static_cast<int>(time_now.tv_sec - start_time.tv_sec);
1191cb0ef41Sopenharmony_ci  if (seconds > 100) {
1201cb0ef41Sopenharmony_ci    if (seconds * 1000 > total_time) return true;
1211cb0ef41Sopenharmony_ci    return false;
1221cb0ef41Sopenharmony_ci  }
1231cb0ef41Sopenharmony_ci  int useconds = static_cast<int>(time_now.tv_usec - start_time.tv_usec);
1241cb0ef41Sopenharmony_ci  if (seconds * 1000000 + useconds > total_time * 1000) {
1251cb0ef41Sopenharmony_ci    return true;
1261cb0ef41Sopenharmony_ci  }
1271cb0ef41Sopenharmony_ci  return false;
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci// A utility class that does a non-hanging waitpid on the child process if we
1311cb0ef41Sopenharmony_ci// bail out of the System() function early.  If you don't ever do a waitpid on
1321cb0ef41Sopenharmony_ci// a subprocess then it turns into one of those annoying 'zombie processes'.
1331cb0ef41Sopenharmony_ciclass ZombieProtector {
1341cb0ef41Sopenharmony_ci public:
1351cb0ef41Sopenharmony_ci  explicit ZombieProtector(int pid) : pid_(pid) {}
1361cb0ef41Sopenharmony_ci  ~ZombieProtector() {
1371cb0ef41Sopenharmony_ci    if (pid_ != 0) waitpid(pid_, nullptr, 0);
1381cb0ef41Sopenharmony_ci  }
1391cb0ef41Sopenharmony_ci  void ChildIsDeadNow() { pid_ = 0; }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci private:
1421cb0ef41Sopenharmony_ci  int pid_;
1431cb0ef41Sopenharmony_ci};
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci// A utility class that closes a file descriptor when it goes out of scope.
1461cb0ef41Sopenharmony_ciclass OpenFDCloser {
1471cb0ef41Sopenharmony_ci public:
1481cb0ef41Sopenharmony_ci  explicit OpenFDCloser(int fd) : fd_(fd) {}
1491cb0ef41Sopenharmony_ci  ~OpenFDCloser() { close(fd_); }
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci private:
1521cb0ef41Sopenharmony_ci  int fd_;
1531cb0ef41Sopenharmony_ci};
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci// A utility class that takes the array of command arguments and puts then in an
1561cb0ef41Sopenharmony_ci// array of new[]ed UTF-8 C strings.  Deallocates them again when it goes out of
1571cb0ef41Sopenharmony_ci// scope.
1581cb0ef41Sopenharmony_ciclass ExecArgs {
1591cb0ef41Sopenharmony_ci public:
1601cb0ef41Sopenharmony_ci  ExecArgs() { exec_args_[0] = nullptr; }
1611cb0ef41Sopenharmony_ci  bool Init(Isolate* isolate, Local<Value> arg0, Local<Array> command_args) {
1621cb0ef41Sopenharmony_ci    String::Utf8Value prog(isolate, arg0);
1631cb0ef41Sopenharmony_ci    if (*prog == nullptr) {
1641cb0ef41Sopenharmony_ci      isolate->ThrowError(
1651cb0ef41Sopenharmony_ci          "os.system(): String conversion of program name failed");
1661cb0ef41Sopenharmony_ci      return false;
1671cb0ef41Sopenharmony_ci    }
1681cb0ef41Sopenharmony_ci    {
1691cb0ef41Sopenharmony_ci      int len = prog.length() + 3;
1701cb0ef41Sopenharmony_ci      char* c_arg = new char[len];
1711cb0ef41Sopenharmony_ci      snprintf(c_arg, len, "%s", *prog);
1721cb0ef41Sopenharmony_ci      exec_args_[0] = c_arg;
1731cb0ef41Sopenharmony_ci    }
1741cb0ef41Sopenharmony_ci    int i = 1;
1751cb0ef41Sopenharmony_ci    for (unsigned j = 0; j < command_args->Length(); i++, j++) {
1761cb0ef41Sopenharmony_ci      Local<Value> arg(
1771cb0ef41Sopenharmony_ci          command_args
1781cb0ef41Sopenharmony_ci              ->Get(isolate->GetCurrentContext(), Integer::New(isolate, j))
1791cb0ef41Sopenharmony_ci              .ToLocalChecked());
1801cb0ef41Sopenharmony_ci      String::Utf8Value utf8_arg(isolate, arg);
1811cb0ef41Sopenharmony_ci      if (*utf8_arg == nullptr) {
1821cb0ef41Sopenharmony_ci        exec_args_[i] = nullptr;  // Consistent state for destructor.
1831cb0ef41Sopenharmony_ci        isolate->ThrowError(
1841cb0ef41Sopenharmony_ci            "os.system(): String conversion of argument failed.");
1851cb0ef41Sopenharmony_ci        return false;
1861cb0ef41Sopenharmony_ci      }
1871cb0ef41Sopenharmony_ci      int len = utf8_arg.length() + 1;
1881cb0ef41Sopenharmony_ci      char* c_arg = new char[len];
1891cb0ef41Sopenharmony_ci      snprintf(c_arg, len, "%s", *utf8_arg);
1901cb0ef41Sopenharmony_ci      exec_args_[i] = c_arg;
1911cb0ef41Sopenharmony_ci    }
1921cb0ef41Sopenharmony_ci    exec_args_[i] = nullptr;
1931cb0ef41Sopenharmony_ci    return true;
1941cb0ef41Sopenharmony_ci  }
1951cb0ef41Sopenharmony_ci  ~ExecArgs() {
1961cb0ef41Sopenharmony_ci    for (unsigned i = 0; i < kMaxArgs; i++) {
1971cb0ef41Sopenharmony_ci      if (exec_args_[i] == nullptr) {
1981cb0ef41Sopenharmony_ci        return;
1991cb0ef41Sopenharmony_ci      }
2001cb0ef41Sopenharmony_ci      delete[] exec_args_[i];
2011cb0ef41Sopenharmony_ci      exec_args_[i] = nullptr;
2021cb0ef41Sopenharmony_ci    }
2031cb0ef41Sopenharmony_ci  }
2041cb0ef41Sopenharmony_ci  static const unsigned kMaxArgs = 1000;
2051cb0ef41Sopenharmony_ci  char* const* arg_array() const { return exec_args_; }
2061cb0ef41Sopenharmony_ci  const char* arg0() const { return exec_args_[0]; }
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci private:
2091cb0ef41Sopenharmony_ci  char* exec_args_[kMaxArgs + 1];
2101cb0ef41Sopenharmony_ci};
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci// Gets the optional timeouts from the arguments to the system() call.
2131cb0ef41Sopenharmony_cistatic bool GetTimeouts(const v8::FunctionCallbackInfo<v8::Value>& args,
2141cb0ef41Sopenharmony_ci                        int* read_timeout, int* total_timeout) {
2151cb0ef41Sopenharmony_ci  if (args.Length() > 3) {
2161cb0ef41Sopenharmony_ci    if (args[3]->IsNumber()) {
2171cb0ef41Sopenharmony_ci      *total_timeout = args[3]
2181cb0ef41Sopenharmony_ci                           ->Int32Value(args.GetIsolate()->GetCurrentContext())
2191cb0ef41Sopenharmony_ci                           .FromJust();
2201cb0ef41Sopenharmony_ci    } else {
2211cb0ef41Sopenharmony_ci      args.GetIsolate()->ThrowError("system: Argument 4 must be a number");
2221cb0ef41Sopenharmony_ci      return false;
2231cb0ef41Sopenharmony_ci    }
2241cb0ef41Sopenharmony_ci  }
2251cb0ef41Sopenharmony_ci  if (args.Length() > 2) {
2261cb0ef41Sopenharmony_ci    if (args[2]->IsNumber()) {
2271cb0ef41Sopenharmony_ci      *read_timeout = args[2]
2281cb0ef41Sopenharmony_ci                          ->Int32Value(args.GetIsolate()->GetCurrentContext())
2291cb0ef41Sopenharmony_ci                          .FromJust();
2301cb0ef41Sopenharmony_ci    } else {
2311cb0ef41Sopenharmony_ci      args.GetIsolate()->ThrowError("system: Argument 3 must be a number");
2321cb0ef41Sopenharmony_ci      return false;
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci  }
2351cb0ef41Sopenharmony_ci  return true;
2361cb0ef41Sopenharmony_ci}
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_cinamespace {
2391cb0ef41Sopenharmony_civ8::Local<v8::String> v8_strerror(v8::Isolate* isolate, int err) {
2401cb0ef41Sopenharmony_ci  return v8::String::NewFromUtf8(isolate, strerror(err)).ToLocalChecked();
2411cb0ef41Sopenharmony_ci}
2421cb0ef41Sopenharmony_ci}  // namespace
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_cistatic const int kReadFD = 0;
2451cb0ef41Sopenharmony_cistatic const int kWriteFD = 1;
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci// This is run in the child process after fork() but before exec().  It normally
2481cb0ef41Sopenharmony_ci// ends with the child process being replaced with the desired child program.
2491cb0ef41Sopenharmony_ci// It only returns if an error occurred.
2501cb0ef41Sopenharmony_cistatic void ExecSubprocess(int* exec_error_fds, int* stdout_fds,
2511cb0ef41Sopenharmony_ci                           const ExecArgs& exec_args) {
2521cb0ef41Sopenharmony_ci  close(exec_error_fds[kReadFD]);  // Don't need this in the child.
2531cb0ef41Sopenharmony_ci  close(stdout_fds[kReadFD]);      // Don't need this in the child.
2541cb0ef41Sopenharmony_ci  close(1);                        // Close stdout.
2551cb0ef41Sopenharmony_ci  dup2(stdout_fds[kWriteFD], 1);   // Dup pipe fd to stdout.
2561cb0ef41Sopenharmony_ci  close(stdout_fds[kWriteFD]);     // Don't need the original fd now.
2571cb0ef41Sopenharmony_ci  fcntl(exec_error_fds[kWriteFD], F_SETFD, FD_CLOEXEC);
2581cb0ef41Sopenharmony_ci  execvp(exec_args.arg0(), exec_args.arg_array());
2591cb0ef41Sopenharmony_ci  // Only get here if the exec failed.  Write errno to the parent to tell
2601cb0ef41Sopenharmony_ci  // them it went wrong.  If it went well the pipe is closed.
2611cb0ef41Sopenharmony_ci  int err = errno;
2621cb0ef41Sopenharmony_ci  ssize_t bytes_written;
2631cb0ef41Sopenharmony_ci  do {
2641cb0ef41Sopenharmony_ci    bytes_written = write(exec_error_fds[kWriteFD], &err, sizeof(err));
2651cb0ef41Sopenharmony_ci  } while (bytes_written == -1 && errno == EINTR);
2661cb0ef41Sopenharmony_ci  // Return (and exit child process).
2671cb0ef41Sopenharmony_ci}
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci// Runs in the parent process.  Checks that the child was able to exec (closing
2701cb0ef41Sopenharmony_ci// the file desriptor), or reports an error if it failed.
2711cb0ef41Sopenharmony_cistatic bool ChildLaunchedOK(Isolate* isolate, int* exec_error_fds) {
2721cb0ef41Sopenharmony_ci  ssize_t bytes_read;
2731cb0ef41Sopenharmony_ci  int err;
2741cb0ef41Sopenharmony_ci  do {
2751cb0ef41Sopenharmony_ci    bytes_read = read(exec_error_fds[kReadFD], &err, sizeof(err));
2761cb0ef41Sopenharmony_ci  } while (bytes_read == -1 && errno == EINTR);
2771cb0ef41Sopenharmony_ci  if (bytes_read != 0) {
2781cb0ef41Sopenharmony_ci    isolate->ThrowError(v8_strerror(isolate, err));
2791cb0ef41Sopenharmony_ci    return false;
2801cb0ef41Sopenharmony_ci  }
2811cb0ef41Sopenharmony_ci  return true;
2821cb0ef41Sopenharmony_ci}
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci// Accumulates the output from the child in a string handle.  Returns true if it
2851cb0ef41Sopenharmony_ci// succeeded or false if an exception was thrown.
2861cb0ef41Sopenharmony_cistatic Local<Value> GetStdout(Isolate* isolate, int child_fd,
2871cb0ef41Sopenharmony_ci                              const struct timeval& start_time,
2881cb0ef41Sopenharmony_ci                              int read_timeout, int total_timeout) {
2891cb0ef41Sopenharmony_ci  Local<String> accumulator = String::Empty(isolate);
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  int fullness = 0;
2921cb0ef41Sopenharmony_ci  static const int kStdoutReadBufferSize = 4096;
2931cb0ef41Sopenharmony_ci  char buffer[kStdoutReadBufferSize];
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci  if (fcntl(child_fd, F_SETFL, O_NONBLOCK) != 0) {
2961cb0ef41Sopenharmony_ci    return isolate->ThrowError(v8_strerror(isolate, errno));
2971cb0ef41Sopenharmony_ci  }
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  int bytes_read;
3001cb0ef41Sopenharmony_ci  do {
3011cb0ef41Sopenharmony_ci    bytes_read = static_cast<int>(
3021cb0ef41Sopenharmony_ci        read(child_fd, buffer + fullness, kStdoutReadBufferSize - fullness));
3031cb0ef41Sopenharmony_ci    if (bytes_read == -1) {
3041cb0ef41Sopenharmony_ci      if (errno == EAGAIN) {
3051cb0ef41Sopenharmony_ci        if (!WaitOnFD(child_fd, read_timeout, total_timeout, start_time) ||
3061cb0ef41Sopenharmony_ci            (TimeIsOut(start_time, total_timeout))) {
3071cb0ef41Sopenharmony_ci          return isolate->ThrowError("Timed out waiting for output");
3081cb0ef41Sopenharmony_ci        }
3091cb0ef41Sopenharmony_ci        continue;
3101cb0ef41Sopenharmony_ci      } else if (errno == EINTR) {
3111cb0ef41Sopenharmony_ci        continue;
3121cb0ef41Sopenharmony_ci      } else {
3131cb0ef41Sopenharmony_ci        break;
3141cb0ef41Sopenharmony_ci      }
3151cb0ef41Sopenharmony_ci    }
3161cb0ef41Sopenharmony_ci    if (bytes_read + fullness > 0) {
3171cb0ef41Sopenharmony_ci      int length = bytes_read == 0 ? bytes_read + fullness
3181cb0ef41Sopenharmony_ci                                   : LengthWithoutIncompleteUtf8(
3191cb0ef41Sopenharmony_ci                                         buffer, bytes_read + fullness);
3201cb0ef41Sopenharmony_ci      Local<String> addition =
3211cb0ef41Sopenharmony_ci          String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
3221cb0ef41Sopenharmony_ci              .ToLocalChecked();
3231cb0ef41Sopenharmony_ci      accumulator = String::Concat(isolate, accumulator, addition);
3241cb0ef41Sopenharmony_ci      fullness = bytes_read + fullness - length;
3251cb0ef41Sopenharmony_ci      memcpy(buffer, buffer + length, fullness);
3261cb0ef41Sopenharmony_ci    }
3271cb0ef41Sopenharmony_ci  } while (bytes_read != 0);
3281cb0ef41Sopenharmony_ci  return accumulator;
3291cb0ef41Sopenharmony_ci}
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci// Modern Linux has the waitid call, which is like waitpid, but more useful
3321cb0ef41Sopenharmony_ci// if you want a timeout.  If we don't have waitid we can't limit the time
3331cb0ef41Sopenharmony_ci// waiting for the process to exit without losing the information about
3341cb0ef41Sopenharmony_ci// whether it exited normally.  In the common case this doesn't matter because
3351cb0ef41Sopenharmony_ci// we don't get here before the child has closed stdout and most programs don't
3361cb0ef41Sopenharmony_ci// do that before they exit.
3371cb0ef41Sopenharmony_ci//
3381cb0ef41Sopenharmony_ci// We're disabling usage of waitid in Mac OS X because it doesn't work for us:
3391cb0ef41Sopenharmony_ci// a parent process hangs on waiting while a child process is already a zombie.
3401cb0ef41Sopenharmony_ci// See http://code.google.com/p/v8/issues/detail?id=401.
3411cb0ef41Sopenharmony_ci#if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__) && \
3421cb0ef41Sopenharmony_ci    !defined(__NetBSD__) && !defined(__Fuchsia__)
3431cb0ef41Sopenharmony_ci#if !defined(__FreeBSD__)
3441cb0ef41Sopenharmony_ci#define HAS_WAITID 1
3451cb0ef41Sopenharmony_ci#endif
3461cb0ef41Sopenharmony_ci#endif
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci// Get exit status of child.
3491cb0ef41Sopenharmony_cistatic bool WaitForChild(Isolate* isolate, int pid,
3501cb0ef41Sopenharmony_ci                         ZombieProtector& child_waiter,
3511cb0ef41Sopenharmony_ci                         const struct timeval& start_time, int read_timeout,
3521cb0ef41Sopenharmony_ci                         int total_timeout) {
3531cb0ef41Sopenharmony_ci#ifdef HAS_WAITID
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci  siginfo_t child_info;
3561cb0ef41Sopenharmony_ci  child_info.si_pid = 0;
3571cb0ef41Sopenharmony_ci  int useconds = 1;
3581cb0ef41Sopenharmony_ci  // Wait for child to exit.
3591cb0ef41Sopenharmony_ci  while (child_info.si_pid == 0) {
3601cb0ef41Sopenharmony_ci    waitid(P_PID, pid, &child_info, WEXITED | WNOHANG | WNOWAIT);
3611cb0ef41Sopenharmony_ci    usleep(useconds);
3621cb0ef41Sopenharmony_ci    if (useconds < 1000000) useconds <<= 1;
3631cb0ef41Sopenharmony_ci    if ((read_timeout != -1 && useconds / 1000 > read_timeout) ||
3641cb0ef41Sopenharmony_ci        (TimeIsOut(start_time, total_timeout))) {
3651cb0ef41Sopenharmony_ci      isolate->ThrowError("Timed out waiting for process to terminate");
3661cb0ef41Sopenharmony_ci      kill(pid, SIGINT);
3671cb0ef41Sopenharmony_ci      return false;
3681cb0ef41Sopenharmony_ci    }
3691cb0ef41Sopenharmony_ci  }
3701cb0ef41Sopenharmony_ci  if (child_info.si_code == CLD_KILLED) {
3711cb0ef41Sopenharmony_ci    char message[999];
3721cb0ef41Sopenharmony_ci    snprintf(message, sizeof(message), "Child killed by signal %d",
3731cb0ef41Sopenharmony_ci             child_info.si_status);
3741cb0ef41Sopenharmony_ci    isolate->ThrowError(message);
3751cb0ef41Sopenharmony_ci    return false;
3761cb0ef41Sopenharmony_ci  }
3771cb0ef41Sopenharmony_ci  if (child_info.si_code == CLD_EXITED && child_info.si_status != 0) {
3781cb0ef41Sopenharmony_ci    char message[999];
3791cb0ef41Sopenharmony_ci    snprintf(message, sizeof(message), "Child exited with status %d",
3801cb0ef41Sopenharmony_ci             child_info.si_status);
3811cb0ef41Sopenharmony_ci    isolate->ThrowError(message);
3821cb0ef41Sopenharmony_ci    return false;
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci#else  // No waitid call.
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci  int child_status;
3881cb0ef41Sopenharmony_ci  waitpid(pid, &child_status, 0);  // We hang here if the child doesn't exit.
3891cb0ef41Sopenharmony_ci  child_waiter.ChildIsDeadNow();
3901cb0ef41Sopenharmony_ci  if (WIFSIGNALED(child_status)) {
3911cb0ef41Sopenharmony_ci    char message[999];
3921cb0ef41Sopenharmony_ci    snprintf(message, sizeof(message), "Child killed by signal %d",
3931cb0ef41Sopenharmony_ci             WTERMSIG(child_status));
3941cb0ef41Sopenharmony_ci    isolate->ThrowError(message);
3951cb0ef41Sopenharmony_ci    return false;
3961cb0ef41Sopenharmony_ci  }
3971cb0ef41Sopenharmony_ci  if (WEXITSTATUS(child_status) != 0) {
3981cb0ef41Sopenharmony_ci    char message[999];
3991cb0ef41Sopenharmony_ci    int exit_status = WEXITSTATUS(child_status);
4001cb0ef41Sopenharmony_ci    snprintf(message, sizeof(message), "Child exited with status %d",
4011cb0ef41Sopenharmony_ci             exit_status);
4021cb0ef41Sopenharmony_ci    isolate->ThrowError(message);
4031cb0ef41Sopenharmony_ci    return false;
4041cb0ef41Sopenharmony_ci  }
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ci#endif  // No waitid call.
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  return true;
4091cb0ef41Sopenharmony_ci}
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci#undef HAS_WAITID
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci// Implementation of the system() function (see d8.h for details).
4141cb0ef41Sopenharmony_civoid Shell::System(const v8::FunctionCallbackInfo<v8::Value>& args) {
4151cb0ef41Sopenharmony_ci  HandleScope scope(args.GetIsolate());
4161cb0ef41Sopenharmony_ci  int read_timeout = -1;
4171cb0ef41Sopenharmony_ci  int total_timeout = -1;
4181cb0ef41Sopenharmony_ci  if (!GetTimeouts(args, &read_timeout, &total_timeout)) return;
4191cb0ef41Sopenharmony_ci  Local<Array> command_args;
4201cb0ef41Sopenharmony_ci  if (args.Length() > 1) {
4211cb0ef41Sopenharmony_ci    if (!args[1]->IsArray()) {
4221cb0ef41Sopenharmony_ci      args.GetIsolate()->ThrowError("system: Argument 2 must be an array");
4231cb0ef41Sopenharmony_ci      return;
4241cb0ef41Sopenharmony_ci    }
4251cb0ef41Sopenharmony_ci    command_args = args[1].As<Array>();
4261cb0ef41Sopenharmony_ci  } else {
4271cb0ef41Sopenharmony_ci    command_args = Array::New(args.GetIsolate(), 0);
4281cb0ef41Sopenharmony_ci  }
4291cb0ef41Sopenharmony_ci  if (command_args->Length() > ExecArgs::kMaxArgs) {
4301cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("Too many arguments to system()");
4311cb0ef41Sopenharmony_ci    return;
4321cb0ef41Sopenharmony_ci  }
4331cb0ef41Sopenharmony_ci  if (args.Length() < 1) {
4341cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("Too few arguments to system()");
4351cb0ef41Sopenharmony_ci    return;
4361cb0ef41Sopenharmony_ci  }
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci  struct timeval start_time;
4391cb0ef41Sopenharmony_ci  gettimeofday(&start_time, nullptr);
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci  ExecArgs exec_args;
4421cb0ef41Sopenharmony_ci  if (!exec_args.Init(args.GetIsolate(), args[0], command_args)) {
4431cb0ef41Sopenharmony_ci    return;
4441cb0ef41Sopenharmony_ci  }
4451cb0ef41Sopenharmony_ci  int exec_error_fds[2];
4461cb0ef41Sopenharmony_ci  int stdout_fds[2];
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci  if (pipe(exec_error_fds) != 0) {
4491cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("pipe syscall failed.");
4501cb0ef41Sopenharmony_ci    return;
4511cb0ef41Sopenharmony_ci  }
4521cb0ef41Sopenharmony_ci  if (pipe(stdout_fds) != 0) {
4531cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("pipe syscall failed.");
4541cb0ef41Sopenharmony_ci    return;
4551cb0ef41Sopenharmony_ci  }
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci  pid_t pid = fork();
4581cb0ef41Sopenharmony_ci  if (pid == 0) {  // Child process.
4591cb0ef41Sopenharmony_ci    ExecSubprocess(exec_error_fds, stdout_fds, exec_args);
4601cb0ef41Sopenharmony_ci    exit(1);
4611cb0ef41Sopenharmony_ci  }
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci  // Parent process.  Ensure that we clean up if we exit this function early.
4641cb0ef41Sopenharmony_ci  ZombieProtector child_waiter(pid);
4651cb0ef41Sopenharmony_ci  close(exec_error_fds[kWriteFD]);
4661cb0ef41Sopenharmony_ci  close(stdout_fds[kWriteFD]);
4671cb0ef41Sopenharmony_ci  OpenFDCloser error_read_closer(exec_error_fds[kReadFD]);
4681cb0ef41Sopenharmony_ci  OpenFDCloser stdout_read_closer(stdout_fds[kReadFD]);
4691cb0ef41Sopenharmony_ci
4701cb0ef41Sopenharmony_ci  Isolate* isolate = args.GetIsolate();
4711cb0ef41Sopenharmony_ci  if (!ChildLaunchedOK(isolate, exec_error_fds)) return;
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  Local<Value> accumulator = GetStdout(isolate, stdout_fds[kReadFD], start_time,
4741cb0ef41Sopenharmony_ci                                       read_timeout, total_timeout);
4751cb0ef41Sopenharmony_ci  if (accumulator->IsUndefined()) {
4761cb0ef41Sopenharmony_ci    kill(pid, SIGINT);  // On timeout, kill the subprocess.
4771cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(accumulator);
4781cb0ef41Sopenharmony_ci    return;
4791cb0ef41Sopenharmony_ci  }
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci  if (!WaitForChild(isolate, pid, child_waiter, start_time, read_timeout,
4821cb0ef41Sopenharmony_ci                    total_timeout)) {
4831cb0ef41Sopenharmony_ci    return;
4841cb0ef41Sopenharmony_ci  }
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(accumulator);
4871cb0ef41Sopenharmony_ci}
4881cb0ef41Sopenharmony_ci
4891cb0ef41Sopenharmony_civoid Shell::ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4901cb0ef41Sopenharmony_ci  if (args.Length() != 1) {
4911cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("chdir() takes one argument");
4921cb0ef41Sopenharmony_ci    return;
4931cb0ef41Sopenharmony_ci  }
4941cb0ef41Sopenharmony_ci  String::Utf8Value directory(args.GetIsolate(), args[0]);
4951cb0ef41Sopenharmony_ci  if (*directory == nullptr) {
4961cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(
4971cb0ef41Sopenharmony_ci        "os.chdir(): String conversion of argument failed.");
4981cb0ef41Sopenharmony_ci    return;
4991cb0ef41Sopenharmony_ci  }
5001cb0ef41Sopenharmony_ci  if (chdir(*directory) != 0) {
5011cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(v8_strerror(args.GetIsolate(), errno));
5021cb0ef41Sopenharmony_ci    return;
5031cb0ef41Sopenharmony_ci  }
5041cb0ef41Sopenharmony_ci}
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_civoid Shell::SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args) {
5071cb0ef41Sopenharmony_ci  if (args.Length() != 1) {
5081cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("umask() takes one argument");
5091cb0ef41Sopenharmony_ci    return;
5101cb0ef41Sopenharmony_ci  }
5111cb0ef41Sopenharmony_ci  if (args[0]->IsNumber()) {
5121cb0ef41Sopenharmony_ci    int previous = umask(
5131cb0ef41Sopenharmony_ci        args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
5141cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(previous);
5151cb0ef41Sopenharmony_ci    return;
5161cb0ef41Sopenharmony_ci  } else {
5171cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("umask() argument must be numeric");
5181cb0ef41Sopenharmony_ci    return;
5191cb0ef41Sopenharmony_ci  }
5201cb0ef41Sopenharmony_ci}
5211cb0ef41Sopenharmony_ci
5221cb0ef41Sopenharmony_cistatic bool CheckItsADirectory(Isolate* isolate, char* directory) {
5231cb0ef41Sopenharmony_ci  struct stat stat_buf;
5241cb0ef41Sopenharmony_ci  int stat_result = stat(directory, &stat_buf);
5251cb0ef41Sopenharmony_ci  if (stat_result != 0) {
5261cb0ef41Sopenharmony_ci    isolate->ThrowError(v8_strerror(isolate, errno));
5271cb0ef41Sopenharmony_ci    return false;
5281cb0ef41Sopenharmony_ci  }
5291cb0ef41Sopenharmony_ci  if ((stat_buf.st_mode & S_IFDIR) != 0) return true;
5301cb0ef41Sopenharmony_ci  isolate->ThrowError(v8_strerror(isolate, EEXIST));
5311cb0ef41Sopenharmony_ci  return false;
5321cb0ef41Sopenharmony_ci}
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci// Returns true for success.  Creates intermediate directories as needed.  No
5351cb0ef41Sopenharmony_ci// error if the directory exists already.
5361cb0ef41Sopenharmony_cistatic bool mkdirp(Isolate* isolate, char* directory, mode_t mask) {
5371cb0ef41Sopenharmony_ci  int result = mkdir(directory, mask);
5381cb0ef41Sopenharmony_ci  if (result == 0) return true;
5391cb0ef41Sopenharmony_ci  if (errno == EEXIST) {
5401cb0ef41Sopenharmony_ci    return CheckItsADirectory(isolate, directory);
5411cb0ef41Sopenharmony_ci  } else if (errno == ENOENT) {  // Intermediate path element is missing.
5421cb0ef41Sopenharmony_ci    char* last_slash = strrchr(directory, '/');
5431cb0ef41Sopenharmony_ci    if (last_slash == nullptr) {
5441cb0ef41Sopenharmony_ci      isolate->ThrowError(v8_strerror(isolate, errno));
5451cb0ef41Sopenharmony_ci      return false;
5461cb0ef41Sopenharmony_ci    }
5471cb0ef41Sopenharmony_ci    *last_slash = 0;
5481cb0ef41Sopenharmony_ci    if (!mkdirp(isolate, directory, mask)) return false;
5491cb0ef41Sopenharmony_ci    *last_slash = '/';
5501cb0ef41Sopenharmony_ci    result = mkdir(directory, mask);
5511cb0ef41Sopenharmony_ci    if (result == 0) return true;
5521cb0ef41Sopenharmony_ci    if (errno == EEXIST) {
5531cb0ef41Sopenharmony_ci      return CheckItsADirectory(isolate, directory);
5541cb0ef41Sopenharmony_ci    }
5551cb0ef41Sopenharmony_ci    isolate->ThrowError(v8_strerror(isolate, errno));
5561cb0ef41Sopenharmony_ci    return false;
5571cb0ef41Sopenharmony_ci  } else {
5581cb0ef41Sopenharmony_ci    isolate->ThrowError(v8_strerror(isolate, errno));
5591cb0ef41Sopenharmony_ci    return false;
5601cb0ef41Sopenharmony_ci  }
5611cb0ef41Sopenharmony_ci}
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_civoid Shell::MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) {
5641cb0ef41Sopenharmony_ci  mode_t mask = 0777;
5651cb0ef41Sopenharmony_ci  if (args.Length() == 2) {
5661cb0ef41Sopenharmony_ci    if (args[1]->IsNumber()) {
5671cb0ef41Sopenharmony_ci      mask = args[1]
5681cb0ef41Sopenharmony_ci                 ->Int32Value(args.GetIsolate()->GetCurrentContext())
5691cb0ef41Sopenharmony_ci                 .FromJust();
5701cb0ef41Sopenharmony_ci    } else {
5711cb0ef41Sopenharmony_ci      args.GetIsolate()->ThrowError("mkdirp() second argument must be numeric");
5721cb0ef41Sopenharmony_ci      return;
5731cb0ef41Sopenharmony_ci    }
5741cb0ef41Sopenharmony_ci  } else if (args.Length() != 1) {
5751cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("mkdirp() takes one or two arguments");
5761cb0ef41Sopenharmony_ci    return;
5771cb0ef41Sopenharmony_ci  }
5781cb0ef41Sopenharmony_ci  String::Utf8Value directory(args.GetIsolate(), args[0]);
5791cb0ef41Sopenharmony_ci  if (*directory == nullptr) {
5801cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(
5811cb0ef41Sopenharmony_ci        "os.mkdirp(): String conversion of argument failed.");
5821cb0ef41Sopenharmony_ci    return;
5831cb0ef41Sopenharmony_ci  }
5841cb0ef41Sopenharmony_ci  mkdirp(args.GetIsolate(), *directory, mask);
5851cb0ef41Sopenharmony_ci}
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_civoid Shell::RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) {
5881cb0ef41Sopenharmony_ci  if (args.Length() != 1) {
5891cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("rmdir() takes one or two arguments");
5901cb0ef41Sopenharmony_ci    return;
5911cb0ef41Sopenharmony_ci  }
5921cb0ef41Sopenharmony_ci  String::Utf8Value directory(args.GetIsolate(), args[0]);
5931cb0ef41Sopenharmony_ci  if (*directory == nullptr) {
5941cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(
5951cb0ef41Sopenharmony_ci        "os.rmdir(): String conversion of argument failed.");
5961cb0ef41Sopenharmony_ci    return;
5971cb0ef41Sopenharmony_ci  }
5981cb0ef41Sopenharmony_ci  rmdir(*directory);
5991cb0ef41Sopenharmony_ci}
6001cb0ef41Sopenharmony_ci
6011cb0ef41Sopenharmony_civoid Shell::SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args) {
6021cb0ef41Sopenharmony_ci  if (args.Length() != 2) {
6031cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("setenv() takes two arguments");
6041cb0ef41Sopenharmony_ci    return;
6051cb0ef41Sopenharmony_ci  }
6061cb0ef41Sopenharmony_ci  String::Utf8Value var(args.GetIsolate(), args[0]);
6071cb0ef41Sopenharmony_ci  String::Utf8Value value(args.GetIsolate(), args[1]);
6081cb0ef41Sopenharmony_ci  if (*var == nullptr) {
6091cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(
6101cb0ef41Sopenharmony_ci        "os.setenv(): String conversion of variable name failed.");
6111cb0ef41Sopenharmony_ci    return;
6121cb0ef41Sopenharmony_ci  }
6131cb0ef41Sopenharmony_ci  if (*value == nullptr) {
6141cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(
6151cb0ef41Sopenharmony_ci        "os.setenv(): String conversion of variable contents failed.");
6161cb0ef41Sopenharmony_ci    return;
6171cb0ef41Sopenharmony_ci  }
6181cb0ef41Sopenharmony_ci  setenv(*var, *value, 1);
6191cb0ef41Sopenharmony_ci}
6201cb0ef41Sopenharmony_ci
6211cb0ef41Sopenharmony_civoid Shell::UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args) {
6221cb0ef41Sopenharmony_ci  if (args.Length() != 1) {
6231cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError("unsetenv() takes one argument");
6241cb0ef41Sopenharmony_ci    return;
6251cb0ef41Sopenharmony_ci  }
6261cb0ef41Sopenharmony_ci  String::Utf8Value var(args.GetIsolate(), args[0]);
6271cb0ef41Sopenharmony_ci  if (*var == nullptr) {
6281cb0ef41Sopenharmony_ci    args.GetIsolate()->ThrowError(
6291cb0ef41Sopenharmony_ci        "os.setenv(): String conversion of variable name failed.");
6301cb0ef41Sopenharmony_ci    return;
6311cb0ef41Sopenharmony_ci  }
6321cb0ef41Sopenharmony_ci  unsetenv(*var);
6331cb0ef41Sopenharmony_ci}
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_cichar* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) {
6361cb0ef41Sopenharmony_ci  DCHECK_GE(Shell::options.read_from_tcp_port, 0);
6371cb0ef41Sopenharmony_ci
6381cb0ef41Sopenharmony_ci  int sockfd = socket(PF_INET, SOCK_STREAM, 0);
6391cb0ef41Sopenharmony_ci  if (sockfd < 0) {
6401cb0ef41Sopenharmony_ci    fprintf(stderr, "Failed to create IPv4 socket\n");
6411cb0ef41Sopenharmony_ci    return nullptr;
6421cb0ef41Sopenharmony_ci  }
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ci  // Create an address for localhost:PORT where PORT is specified by the shell
6451cb0ef41Sopenharmony_ci  // option --read-from-tcp-port.
6461cb0ef41Sopenharmony_ci  sockaddr_in serv_addr;
6471cb0ef41Sopenharmony_ci  memset(&serv_addr, 0, sizeof(sockaddr_in));
6481cb0ef41Sopenharmony_ci  serv_addr.sin_family = AF_INET;
6491cb0ef41Sopenharmony_ci  serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6501cb0ef41Sopenharmony_ci  serv_addr.sin_port = htons(Shell::options.read_from_tcp_port);
6511cb0ef41Sopenharmony_ci
6521cb0ef41Sopenharmony_ci  if (connect(sockfd, reinterpret_cast<sockaddr*>(&serv_addr),
6531cb0ef41Sopenharmony_ci              sizeof(serv_addr)) < 0) {
6541cb0ef41Sopenharmony_ci    fprintf(stderr, "Failed to connect to localhost:%d\n",
6551cb0ef41Sopenharmony_ci            Shell::options.read_from_tcp_port.get());
6561cb0ef41Sopenharmony_ci    close(sockfd);
6571cb0ef41Sopenharmony_ci    return nullptr;
6581cb0ef41Sopenharmony_ci  }
6591cb0ef41Sopenharmony_ci
6601cb0ef41Sopenharmony_ci  // The file server follows the simple protocol for requesting and receiving
6611cb0ef41Sopenharmony_ci  // a file with a given filename:
6621cb0ef41Sopenharmony_ci  //
6631cb0ef41Sopenharmony_ci  //   REQUEST client -> server: {filename}"\0"
6641cb0ef41Sopenharmony_ci  //   RESPONSE server -> client: {4-byte file-length}{file contents}
6651cb0ef41Sopenharmony_ci  //
6661cb0ef41Sopenharmony_ci  // i.e. the request sends the filename with a null terminator, and response
6671cb0ef41Sopenharmony_ci  // sends the file contents by sending the length (as a 4-byte big-endian
6681cb0ef41Sopenharmony_ci  // value) and the contents.
6691cb0ef41Sopenharmony_ci
6701cb0ef41Sopenharmony_ci  // If the file length is <0, there was an error sending the file, and the
6711cb0ef41Sopenharmony_ci  // rest of the response is undefined (and may, in the future, contain an error
6721cb0ef41Sopenharmony_ci  // message). The socket should be closed to avoid trying to interpret the
6731cb0ef41Sopenharmony_ci  // undefined data.
6741cb0ef41Sopenharmony_ci
6751cb0ef41Sopenharmony_ci  // REQUEST
6761cb0ef41Sopenharmony_ci  // Send the filename.
6771cb0ef41Sopenharmony_ci  size_t sent_len = 0;
6781cb0ef41Sopenharmony_ci  size_t name_len = strlen(name) + 1;  // Includes the null terminator
6791cb0ef41Sopenharmony_ci  while (sent_len < name_len) {
6801cb0ef41Sopenharmony_ci    ssize_t sent_now = send(sockfd, name + sent_len, name_len - sent_len, 0);
6811cb0ef41Sopenharmony_ci    if (sent_now < 0) {
6821cb0ef41Sopenharmony_ci      fprintf(stderr, "Failed to send %s to localhost:%d\n", name,
6831cb0ef41Sopenharmony_ci              Shell::options.read_from_tcp_port.get());
6841cb0ef41Sopenharmony_ci      close(sockfd);
6851cb0ef41Sopenharmony_ci      return nullptr;
6861cb0ef41Sopenharmony_ci    }
6871cb0ef41Sopenharmony_ci    sent_len += sent_now;
6881cb0ef41Sopenharmony_ci  }
6891cb0ef41Sopenharmony_ci
6901cb0ef41Sopenharmony_ci  // RESPONSE
6911cb0ef41Sopenharmony_ci  // Receive the file.
6921cb0ef41Sopenharmony_ci  ssize_t received = 0;
6931cb0ef41Sopenharmony_ci
6941cb0ef41Sopenharmony_ci  // First, read the (zero-terminated) file length.
6951cb0ef41Sopenharmony_ci  uint32_t big_endian_file_length;
6961cb0ef41Sopenharmony_ci  received = recv(sockfd, &big_endian_file_length, 4, 0);
6971cb0ef41Sopenharmony_ci  // We need those 4 bytes to read off the file length.
6981cb0ef41Sopenharmony_ci  if (received < 4) {
6991cb0ef41Sopenharmony_ci    fprintf(stderr, "Failed to receive %s's length from localhost:%d\n", name,
7001cb0ef41Sopenharmony_ci            Shell::options.read_from_tcp_port.get());
7011cb0ef41Sopenharmony_ci    close(sockfd);
7021cb0ef41Sopenharmony_ci    return nullptr;
7031cb0ef41Sopenharmony_ci  }
7041cb0ef41Sopenharmony_ci  // Reinterpretet the received file length as a signed big-endian integer.
7051cb0ef41Sopenharmony_ci  int32_t file_length = bit_cast<int32_t>(htonl(big_endian_file_length));
7061cb0ef41Sopenharmony_ci
7071cb0ef41Sopenharmony_ci  if (file_length < 0) {
7081cb0ef41Sopenharmony_ci    fprintf(stderr, "Received length %d for %s from localhost:%d\n",
7091cb0ef41Sopenharmony_ci            file_length, name, Shell::options.read_from_tcp_port.get());
7101cb0ef41Sopenharmony_ci    close(sockfd);
7111cb0ef41Sopenharmony_ci    return nullptr;
7121cb0ef41Sopenharmony_ci  }
7131cb0ef41Sopenharmony_ci
7141cb0ef41Sopenharmony_ci  // Allocate the output array.
7151cb0ef41Sopenharmony_ci  char* chars = new char[file_length];
7161cb0ef41Sopenharmony_ci
7171cb0ef41Sopenharmony_ci  // Now keep receiving and copying until the whole file is received.
7181cb0ef41Sopenharmony_ci  ssize_t total_received = 0;
7191cb0ef41Sopenharmony_ci  while (total_received < file_length) {
7201cb0ef41Sopenharmony_ci    received =
7211cb0ef41Sopenharmony_ci        recv(sockfd, chars + total_received, file_length - total_received, 0);
7221cb0ef41Sopenharmony_ci    if (received < 0) {
7231cb0ef41Sopenharmony_ci      fprintf(stderr, "Failed to receive %s from localhost:%d\n", name,
7241cb0ef41Sopenharmony_ci              Shell::options.read_from_tcp_port.get());
7251cb0ef41Sopenharmony_ci      close(sockfd);
7261cb0ef41Sopenharmony_ci      delete[] chars;
7271cb0ef41Sopenharmony_ci      return nullptr;
7281cb0ef41Sopenharmony_ci    }
7291cb0ef41Sopenharmony_ci    total_received += received;
7301cb0ef41Sopenharmony_ci  }
7311cb0ef41Sopenharmony_ci
7321cb0ef41Sopenharmony_ci  close(sockfd);
7331cb0ef41Sopenharmony_ci  *size_out = file_length;
7341cb0ef41Sopenharmony_ci  return chars;
7351cb0ef41Sopenharmony_ci}
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_civoid Shell::AddOSMethods(Isolate* isolate, Local<ObjectTemplate> os_templ) {
7381cb0ef41Sopenharmony_ci  if (options.enable_os_system) {
7391cb0ef41Sopenharmony_ci    os_templ->Set(isolate, "system", FunctionTemplate::New(isolate, System));
7401cb0ef41Sopenharmony_ci  }
7411cb0ef41Sopenharmony_ci  os_templ->Set(isolate, "chdir",
7421cb0ef41Sopenharmony_ci                FunctionTemplate::New(isolate, ChangeDirectory));
7431cb0ef41Sopenharmony_ci  os_templ->Set(isolate, "setenv",
7441cb0ef41Sopenharmony_ci                FunctionTemplate::New(isolate, SetEnvironment));
7451cb0ef41Sopenharmony_ci  os_templ->Set(isolate, "unsetenv",
7461cb0ef41Sopenharmony_ci                FunctionTemplate::New(isolate, UnsetEnvironment));
7471cb0ef41Sopenharmony_ci  os_templ->Set(isolate, "umask", FunctionTemplate::New(isolate, SetUMask));
7481cb0ef41Sopenharmony_ci  os_templ->Set(isolate, "mkdirp",
7491cb0ef41Sopenharmony_ci                FunctionTemplate::New(isolate, MakeDirectory));
7501cb0ef41Sopenharmony_ci  os_templ->Set(isolate, "rmdir",
7511cb0ef41Sopenharmony_ci                FunctionTemplate::New(isolate, RemoveDirectory));
7521cb0ef41Sopenharmony_ci}
7531cb0ef41Sopenharmony_ci
7541cb0ef41Sopenharmony_ci}  // namespace v8
755