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