1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2009 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h> 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <errno.h> 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h> 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/stat.h> 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/time.h> 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <time.h> 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <unistd.h> 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <fcntl.h> 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/wait.h> 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <signal.h> 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "d8.h" 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "d8-debug.h" 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "debug.h" 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// If the buffer ends in the middle of a UTF-8 sequence then we return 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the length of the string up to but not including the incomplete UTF-8 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// sequence. If the buffer ends with a valid UTF-8 sequence then we 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// return the whole buffer. 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int LengthWithoutIncompleteUtf8(char* buffer, int len) { 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int answer = len; 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 1-byte encoding. 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8SingleByteMask = 0x80; 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8SingleByteValue = 0x00; 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 2-byte encoding. 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8TwoByteMask = 0xe0; 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8TwoByteValue = 0xc0; 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 3-byte encoding. 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8ThreeByteMask = 0xf0; 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8ThreeByteValue = 0xe0; 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 4-byte encoding. 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8FourByteMask = 0xf8; 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kUtf8FourByteValue = 0xf0; 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Subsequent bytes of a multi-byte encoding. 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kMultiByteMask = 0xc0; 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kMultiByteValue = 0x80; 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int multi_byte_bytes_seen = 0; 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (answer > 0) { 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int c = buffer[answer - 1]; 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ends in valid single-byte sequence? 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((c & kUtf8SingleByteMask) == kUtf8SingleByteValue) return answer; 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Ends in one or more subsequent bytes of a multi-byte value? 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((c & kMultiByteMask) == kMultiByteValue) { 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block multi_byte_bytes_seen++; 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block answer--; 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((c & kUtf8TwoByteMask) == kUtf8TwoByteValue) { 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (multi_byte_bytes_seen >= 1) { 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer + 2; 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer - 1; 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if ((c & kUtf8ThreeByteMask) == kUtf8ThreeByteValue) { 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (multi_byte_bytes_seen >= 2) { 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer + 3; 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer - 1; 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if ((c & kUtf8FourByteMask) == kUtf8FourByteValue) { 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (multi_byte_bytes_seen >= 3) { 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer + 4; 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer - 1; 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return answer; // Malformed UTF-8. 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 0; 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Suspends the thread until there is data available from the child process. 105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Returns false on timeout, true on data ready. 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool WaitOnFD(int fd, 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int read_timeout, 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int total_timeout, 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval& start_time) { 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fd_set readfds, writefds, exceptfds; 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval timeout; 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int gone = 0; 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (total_timeout != -1) { 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval time_now; 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block gettimeofday(&time_now, NULL); 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int seconds = time_now.tv_sec - start_time.tv_sec; 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block gone = seconds * 1000 + (time_now.tv_usec - start_time.tv_usec) / 1000; 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (gone >= total_timeout) return false; 119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FD_ZERO(&readfds); 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FD_ZERO(&writefds); 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FD_ZERO(&exceptfds); 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FD_SET(fd, &readfds); 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FD_SET(fd, &exceptfds); 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (read_timeout == -1 || 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (total_timeout != -1 && total_timeout - gone < read_timeout)) { 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block read_timeout = total_timeout - gone; 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block timeout.tv_usec = (read_timeout % 1000) * 1000; 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block timeout.tv_sec = read_timeout / 1000; 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int number_of_fds_ready = select(fd + 1, 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &readfds, 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &writefds, 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &exceptfds, 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block read_timeout != -1 ? &timeout : NULL); 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return number_of_fds_ready == 1; 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Checks whether we ran out of time on the timeout. Returns true if we ran out 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// of time, false if we still have time. 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool TimeIsOut(const struct timeval& start_time, const int& total_time) { 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (total_time == -1) return false; 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval time_now; 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block gettimeofday(&time_now, NULL); 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Careful about overflow. 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int seconds = time_now.tv_sec - start_time.tv_sec; 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (seconds > 100) { 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (seconds * 1000 > total_time) return true; 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int useconds = time_now.tv_usec - start_time.tv_usec; 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (seconds * 1000000 + useconds > total_time * 1000) { 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A utility class that does a non-hanging waitpid on the child process if we 161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// bail out of the System() function early. If you don't ever do a waitpid on 162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// a subprocess then it turns into one of those annoying 'zombie processes'. 163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ZombieProtector { 164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block explicit ZombieProtector(int pid): pid_(pid) { } 166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ~ZombieProtector() { if (pid_ != 0) waitpid(pid_, NULL, 0); } 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void ChildIsDeadNow() { pid_ = 0; } 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int pid_; 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A utility class that closes a file descriptor when it goes out of scope. 174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass OpenFDCloser { 175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block explicit OpenFDCloser(int fd): fd_(fd) { } 177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ~OpenFDCloser() { close(fd_); } 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int fd_; 180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A utility class that takes the array of command arguments and puts then in an 184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// array of new[]ed UTF-8 C strings. Deallocates them again when it goes out of 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// scope. 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ExecArgs { 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExecArgs() { 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exec_args_[0] = NULL; 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool Init(Handle<Value> arg0, Handle<Array> command_args) { 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value prog(arg0); 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*prog == NULL) { 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "os.system(): String conversion of program name failed"; 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(message)); 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int len = prog.length() + 3; 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* c_arg = new char[len]; 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(c_arg, len, "%s", *prog); 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exec_args_[0] = c_arg; 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int i = 1; 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (unsigned j = 0; j < command_args->Length(); i++, j++) { 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Value> arg(command_args->Get(Integer::New(j))); 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value utf8_arg(arg); 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*utf8_arg == NULL) { 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exec_args_[i] = NULL; // Consistent state for destructor. 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "os.system(): String conversion of argument failed."; 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(message)); 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int len = utf8_arg.length() + 1; 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* c_arg = new char[len]; 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(c_arg, len, "%s", *utf8_arg); 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exec_args_[i] = c_arg; 218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exec_args_[i] = NULL; 220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ~ExecArgs() { 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (unsigned i = 0; i < kMaxArgs; i++) { 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (exec_args_[i] == NULL) { 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block delete [] exec_args_[i]; 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exec_args_[i] = 0; 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const unsigned kMaxArgs = 1000; 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char** arg_array() { return exec_args_; } 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* arg0() { return exec_args_[0]; } 234589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* exec_args_[kMaxArgs + 1]; 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Gets the optional timeouts from the arguments to the system() call. 241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool GetTimeouts(const Arguments& args, 242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int* read_timeout, 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int* total_timeout) { 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() > 3) { 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args[3]->IsNumber()) { 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *total_timeout = args[3]->Int32Value(); 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New("system: Argument 4 must be a number")); 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() > 2) { 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args[2]->IsNumber()) { 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *read_timeout = args[2]->Int32Value(); 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New("system: Argument 3 must be a number")); 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kReadFD = 0; 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kWriteFD = 1; 266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This is run in the child process after fork() but before exec(). It normally 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ends with the child process being replaced with the desired child program. 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// It only returns if an error occurred. 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ExecSubprocess(int* exec_error_fds, 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int* stdout_fds, 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExecArgs& exec_args) { 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block close(exec_error_fds[kReadFD]); // Don't need this in the child. 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block close(stdout_fds[kReadFD]); // Don't need this in the child. 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block close(1); // Close stdout. 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dup2(stdout_fds[kWriteFD], 1); // Dup pipe fd to stdout. 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block close(stdout_fds[kWriteFD]); // Don't need the original fd now. 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fcntl(exec_error_fds[kWriteFD], F_SETFD, FD_CLOEXEC); 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block execvp(exec_args.arg0(), exec_args.arg_array()); 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Only get here if the exec failed. Write errno to the parent to tell 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // them it went wrong. If it went well the pipe is closed. 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int err = errno; 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int bytes_written; 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block do { 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bytes_written = write(exec_error_fds[kWriteFD], &err, sizeof(err)); 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } while (bytes_written == -1 && errno == EINTR); 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return (and exit child process). 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Runs in the parent process. Checks that the child was able to exec (closing 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the file desriptor), or reports an error if it failed. 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool ChildLaunchedOK(int* exec_error_fds) { 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int bytes_read; 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int err; 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block do { 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bytes_read = read(exec_error_fds[kReadFD], &err, sizeof(err)); 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } while (bytes_read == -1 && errno == EINTR); 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (bytes_read != 0) { 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(strerror(err))); 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Accumulates the output from the child in a string handle. Returns true if it 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// succeeded or false if an exception was thrown. 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Handle<Value> GetStdout(int child_fd, 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval& start_time, 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int read_timeout, 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int total_timeout) { 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<String> accumulator = String::Empty(); 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int fullness = 0; 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kStdoutReadBufferSize = 4096; 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char buffer[kStdoutReadBufferSize]; 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (fcntl(child_fd, F_SETFL, O_NONBLOCK) != 0) { 321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(strerror(errno))); 322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int bytes_read; 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block do { 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bytes_read = read(child_fd, 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block buffer + fullness, 328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block kStdoutReadBufferSize - fullness); 329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (bytes_read == -1) { 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (errno == EAGAIN) { 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!WaitOnFD(child_fd, 332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block read_timeout, 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block total_timeout, 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_time) || 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (TimeIsOut(start_time, total_timeout))) { 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New("Timed out waiting for output")); 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue; 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (errno == EINTR) { 340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue; 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (bytes_read + fullness > 0) { 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int length = bytes_read == 0 ? 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bytes_read + fullness : 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LengthWithoutIncompleteUtf8(buffer, bytes_read + fullness); 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<String> addition = String::New(buffer, length); 3503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch accumulator = String::Concat(accumulator, addition); 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fullness = bytes_read + fullness - length; 352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block memcpy(buffer, buffer + length, fullness); 353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } while (bytes_read != 0); 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return accumulator; 356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Modern Linux has the waitid call, which is like waitpid, but more useful 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// if you want a timeout. If we don't have waitid we can't limit the time 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// waiting for the process to exit without losing the information about 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// whether it exited normally. In the common case this doesn't matter because 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// we don't get here before the child has closed stdout and most programs don't 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// do that before they exit. 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We're disabling usage of waitid in Mac OS X because it doens't work for us: 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// a parent process hangs on waiting while a child process is already a zombie. 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// See http://code.google.com/p/v8/issues/detail?id=401. 3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__) \ 3703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch && !defined(__NetBSD__) 37144f0eee88ff00398ff7f715fab053374d808c90dSteve Block#if !defined(__FreeBSD__) 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define HAS_WAITID 1 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 37444f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif 375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Get exit status of child. 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool WaitForChild(int pid, 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ZombieProtector& child_waiter, 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval& start_time, 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int read_timeout, 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int total_timeout) { 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef HAS_WAITID 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block siginfo_t child_info; 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block child_info.si_pid = 0; 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int useconds = 1; 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Wait for child to exit. 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (child_info.si_pid == 0) { 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block waitid(P_PID, pid, &child_info, WEXITED | WNOHANG | WNOWAIT); 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block usleep(useconds); 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (useconds < 1000000) useconds <<= 1; 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((read_timeout != -1 && useconds / 1000 > read_timeout) || 394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (TimeIsOut(start_time, total_timeout))) { 395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New("Timed out waiting for process to terminate")); 396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block kill(pid, SIGINT); 397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (child_info.si_code == CLD_KILLED) { 401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char message[999]; 402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(message, 403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sizeof(message), 404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Child killed by signal %d", 405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block child_info.si_status); 406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(message)); 407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (child_info.si_code == CLD_EXITED && child_info.si_status != 0) { 410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char message[999]; 411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(message, 412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sizeof(message), 413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Child exited with status %d", 414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block child_info.si_status); 415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(message)); 416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else // No waitid call. 420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int child_status; 422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block waitpid(pid, &child_status, 0); // We hang here if the child doesn't exit. 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block child_waiter.ChildIsDeadNow(); 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (WIFSIGNALED(child_status)) { 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char message[999]; 426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(message, 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sizeof(message), 428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Child killed by signal %d", 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block WTERMSIG(child_status)); 430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(message)); 431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (WEXITSTATUS(child_status) != 0) { 434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char message[999]; 435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int exit_status = WEXITSTATUS(child_status); 436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(message, 437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sizeof(message), 438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Child exited with status %d", 439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit_status); 440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(message)); 441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif // No waitid call. 445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Implementation of the system() function (see d8.h for details). 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Value> Shell::System(const Arguments& args) { 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block HandleScope scope; 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int read_timeout = -1; 454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int total_timeout = -1; 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!GetTimeouts(args, &read_timeout, &total_timeout)) return v8::Undefined(); 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Array> command_args; 457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() > 1) { 458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!args[1]->IsArray()) { 459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New("system: Argument 2 must be an array")); 460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block command_args = Handle<Array>::Cast(args[1]); 462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block command_args = Array::New(0); 464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (command_args->Length() > ExecArgs::kMaxArgs) { 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New("Too many arguments to system()")); 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() < 1) { 469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New("Too few arguments to system()")); 470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval start_time; 473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block gettimeofday(&start_time, NULL); 474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExecArgs exec_args; 476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!exec_args.Init(args[0], command_args)) { 477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return v8::Undefined(); 478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int exec_error_fds[2]; 480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int stdout_fds[2]; 481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (pipe(exec_error_fds) != 0) { 483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New("pipe syscall failed.")); 484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (pipe(stdout_fds) != 0) { 486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New("pipe syscall failed.")); 487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pid_t pid = fork(); 490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (pid == 0) { // Child process. 491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExecSubprocess(exec_error_fds, stdout_fds, exec_args); 492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block exit(1); 493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Parent process. Ensure that we clean up if we exit this function early. 496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ZombieProtector child_waiter(pid); 497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block close(exec_error_fds[kWriteFD]); 498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block close(stdout_fds[kWriteFD]); 499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OpenFDCloser error_read_closer(exec_error_fds[kReadFD]); 500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block OpenFDCloser stdout_read_closer(stdout_fds[kReadFD]); 501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ChildLaunchedOK(exec_error_fds)) return v8::Undefined(); 503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Value> accumulator = GetStdout(stdout_fds[kReadFD], 505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_time, 506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block read_timeout, 507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block total_timeout); 508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (accumulator->IsUndefined()) { 509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block kill(pid, SIGINT); // On timeout, kill the subprocess. 510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return accumulator; 511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!WaitForChild(pid, 514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block child_waiter, 515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_time, 516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block read_timeout, 517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block total_timeout)) { 518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return v8::Undefined(); 519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return scope.Close(accumulator); 522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Value> Shell::ChangeDirectory(const Arguments& args) { 526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() != 1) { 527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "chdir() takes one argument"; 528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value directory(args[0]); 531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*directory == NULL) { 532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "os.chdir(): String conversion of argument failed."; 533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (chdir(*directory) != 0) { 536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(strerror(errno))); 537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return v8::Undefined(); 539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Value> Shell::SetUMask(const Arguments& args) { 543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() != 1) { 544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "umask() takes one argument"; 545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args[0]->IsNumber()) { 548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block mode_t mask = args[0]->Int32Value(); 549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int previous = umask(mask); 550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return Number::New(previous); 551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "umask() argument must be numeric"; 553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool CheckItsADirectory(char* directory) { 559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct stat stat_buf; 560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int stat_result = stat(directory, &stat_buf); 561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (stat_result != 0) { 562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(strerror(errno))); 563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((stat_buf.st_mode & S_IFDIR) != 0) return true; 566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(strerror(EEXIST))); 567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Returns true for success. Creates intermediate directories as needed. No 572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// error if the directory exists already. 573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool mkdirp(char* directory, mode_t mask) { 574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = mkdir(directory, mask); 575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result == 0) return true; 576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (errno == EEXIST) { 577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return CheckItsADirectory(directory); 578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (errno == ENOENT) { // Intermediate path element is missing. 579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* last_slash = strrchr(directory, '/'); 580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (last_slash == NULL) { 581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(strerror(errno))); 582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *last_slash = 0; 585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!mkdirp(directory, mask)) return false; 586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *last_slash = '/'; 587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = mkdir(directory, mask); 588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result == 0) return true; 589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (errno == EEXIST) { 590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return CheckItsADirectory(directory); 591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(strerror(errno))); 593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ThrowException(String::New(strerror(errno))); 596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Value> Shell::MakeDirectory(const Arguments& args) { 602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block mode_t mask = 0777; 603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() == 2) { 604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args[1]->IsNumber()) { 605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block mask = args[1]->Int32Value(); 606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "mkdirp() second argument must be numeric"; 608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (args.Length() != 1) { 611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "mkdirp() takes one or two arguments"; 612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value directory(args[0]); 615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*directory == NULL) { 616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "os.mkdirp(): String conversion of argument failed."; 617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block mkdirp(*directory, mask); 620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return v8::Undefined(); 621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Value> Shell::RemoveDirectory(const Arguments& args) { 625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() != 1) { 626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "rmdir() takes one or two arguments"; 627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value directory(args[0]); 630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*directory == NULL) { 631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "os.rmdir(): String conversion of argument failed."; 632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rmdir(*directory); 635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return v8::Undefined(); 636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Value> Shell::SetEnvironment(const Arguments& args) { 640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (args.Length() != 2) { 641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = "setenv() takes two arguments"; 642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value var(args[0]); 645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String::Utf8Value value(args[1]); 646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*var == NULL) { 647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = 648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "os.setenv(): String conversion of variable name failed."; 649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (*value == NULL) { 652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* message = 653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "os.setenv(): String conversion of variable contents failed."; 654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ThrowException(String::New(message)); 655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block setenv(*var, *value, 1); 657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return v8::Undefined(); 658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6616ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockHandle<Value> Shell::UnsetEnvironment(const Arguments& args) { 6626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (args.Length() != 1) { 6636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const char* message = "unsetenv() takes one argument"; 6646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block return ThrowException(String::New(message)); 6656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 6666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block String::Utf8Value var(args[0]); 6676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (*var == NULL) { 6686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const char* message = 6696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block "os.setenv(): String conversion of variable name failed."; 6706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block return ThrowException(String::New(message)); 6716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 6726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block unsetenv(*var); 6736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block return v8::Undefined(); 6746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 6756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 6766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Shell::AddOSMethods(Handle<ObjectTemplate> os_templ) { 678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block os_templ->Set(String::New("system"), FunctionTemplate::New(System)); 679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory)); 680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment)); 6816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block os_templ->Set(String::New("unsetenv"), 6826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FunctionTemplate::New(UnsetEnvironment)); 683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block os_templ->Set(String::New("umask"), FunctionTemplate::New(SetUMask)); 684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block os_templ->Set(String::New("mkdirp"), FunctionTemplate::New(MakeDirectory)); 685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block os_templ->Set(String::New("rmdir"), FunctionTemplate::New(RemoveDirectory)); 686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} // namespace v8 689