31 #include <sys/types.h>
53 static int LengthWithoutIncompleteUtf8(
char* buffer,
int len) {
56 static const int kUtf8SingleByteMask = 0x80;
57 static const int kUtf8SingleByteValue = 0x00;
59 static const int kUtf8TwoByteMask = 0xe0;
60 static const int kUtf8TwoByteValue = 0xc0;
62 static const int kUtf8ThreeByteMask = 0xf0;
63 static const int kUtf8ThreeByteValue = 0xe0;
65 static const int kUtf8FourByteMask = 0xf8;
66 static const int kUtf8FourByteValue = 0xf0;
68 static const int kMultiByteMask = 0xc0;
69 static const int kMultiByteValue = 0x80;
70 int multi_byte_bytes_seen = 0;
72 int c = buffer[answer - 1];
74 if ((c & kUtf8SingleByteMask) == kUtf8SingleByteValue)
return answer;
76 if ((c & kMultiByteMask) == kMultiByteValue) {
77 multi_byte_bytes_seen++;
80 if ((c & kUtf8TwoByteMask) == kUtf8TwoByteValue) {
81 if (multi_byte_bytes_seen >= 1) {
85 }
else if ((c & kUtf8ThreeByteMask) == kUtf8ThreeByteValue) {
86 if (multi_byte_bytes_seen >= 2) {
90 }
else if ((c & kUtf8FourByteMask) == kUtf8FourByteValue) {
91 if (multi_byte_bytes_seen >= 3) {
106 static bool WaitOnFD(
int fd,
109 struct timeval& start_time) {
110 fd_set readfds, writefds, exceptfds;
111 struct timeval timeout;
113 if (total_timeout != -1) {
114 struct timeval time_now;
115 gettimeofday(&time_now,
NULL);
116 int seconds = time_now.tv_sec - start_time.tv_sec;
117 gone = seconds * 1000 + (time_now.tv_usec - start_time.tv_usec) / 1000;
118 if (gone >= total_timeout)
return false;
123 FD_SET(fd, &readfds);
124 FD_SET(fd, &exceptfds);
125 if (read_timeout == -1 ||
126 (total_timeout != -1 && total_timeout - gone < read_timeout)) {
127 read_timeout = total_timeout - gone;
129 timeout.tv_usec = (read_timeout % 1000) * 1000;
130 timeout.tv_sec = read_timeout / 1000;
131 int number_of_fds_ready = select(fd + 1,
135 read_timeout != -1 ? &timeout :
NULL);
136 return number_of_fds_ready == 1;
142 static bool TimeIsOut(
const struct timeval& start_time,
const int& total_time) {
143 if (total_time == -1)
return false;
144 struct timeval time_now;
145 gettimeofday(&time_now,
NULL);
147 int seconds = time_now.tv_sec - start_time.tv_sec;
149 if (seconds * 1000 > total_time)
return true;
152 int useconds = time_now.tv_usec - start_time.tv_usec;
153 if (seconds * 1000000 + useconds > total_time * 1000) {
189 exec_args_[0] =
NULL;
194 const char* message =
195 "os.system(): String conversion of program name failed";
199 int len = prog.
length() + 3;
200 char* c_arg =
new char[len];
201 snprintf(c_arg, len,
"%s", *prog);
202 exec_args_[0] = c_arg;
204 for (
unsigned j = 0; j < command_args->Length(); i++, j++) {
207 if (*utf8_arg ==
NULL) {
208 exec_args_[i] =
NULL;
209 const char* message =
210 "os.system(): String conversion of argument failed.";
214 int len = utf8_arg.length() + 1;
215 char* c_arg =
new char[len];
216 snprintf(c_arg, len,
"%s", *utf8_arg);
217 exec_args_[i] = c_arg;
219 exec_args_[i] =
NULL;
223 for (
unsigned i = 0; i <
kMaxArgs; i++) {
224 if (exec_args_[i] ==
NULL) {
227 delete [] exec_args_[i];
233 char*
arg0() {
return exec_args_[0]; }
241 static bool GetTimeouts(
const Arguments& args,
243 int* total_timeout) {
244 if (args.Length() > 3) {
245 if (args[3]->IsNumber()) {
246 *total_timeout = args[3]->Int32Value();
252 if (args.Length() > 2) {
253 if (args[2]->IsNumber()) {
254 *read_timeout = args[2]->Int32Value();
264 static const int kReadFD = 0;
265 static const int kWriteFD = 1;
271 static void ExecSubprocess(
int* exec_error_fds,
273 ExecArgs& exec_args) {
274 close(exec_error_fds[kReadFD]);
275 close(stdout_fds[kReadFD]);
277 dup2(stdout_fds[kWriteFD], 1);
278 close(stdout_fds[kWriteFD]);
279 fcntl(exec_error_fds[kWriteFD], F_SETFD, FD_CLOEXEC);
280 execvp(exec_args.arg0(), exec_args.arg_array());
286 bytes_written = write(exec_error_fds[kWriteFD], &err,
sizeof(err));
287 }
while (bytes_written == -1 && errno == EINTR);
294 static bool ChildLaunchedOK(
int* exec_error_fds) {
298 bytes_read = read(exec_error_fds[kReadFD], &err,
sizeof(err));
299 }
while (bytes_read == -1 && errno == EINTR);
300 if (bytes_read != 0) {
310 static Handle<Value> GetStdout(
int child_fd,
311 struct timeval& start_time,
317 static const int kStdoutReadBufferSize = 4096;
318 char buffer[kStdoutReadBufferSize];
320 if (fcntl(child_fd, F_SETFL, O_NONBLOCK) != 0) {
326 bytes_read = read(child_fd,
328 kStdoutReadBufferSize - fullness);
329 if (bytes_read == -1) {
330 if (errno == EAGAIN) {
331 if (!WaitOnFD(child_fd,
335 (TimeIsOut(start_time, total_timeout))) {
339 }
else if (errno == EINTR) {
345 if (bytes_read + fullness > 0) {
346 int length = bytes_read == 0 ?
347 bytes_read + fullness :
348 LengthWithoutIncompleteUtf8(buffer, bytes_read + fullness);
349 Handle<String> addition =
String::New(buffer, length);
351 fullness = bytes_read + fullness - length;
352 memcpy(buffer, buffer + length, fullness);
354 }
while (bytes_read != 0);
369 #if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__) \
370 && !defined(__NetBSD__)
371 #if !defined(__FreeBSD__)
378 static bool WaitForChild(
int pid,
379 ZombieProtector& child_waiter,
380 struct timeval& start_time,
385 siginfo_t child_info;
386 child_info.si_pid = 0;
389 while (child_info.si_pid == 0) {
390 waitid(P_PID, pid, &child_info, WEXITED | WNOHANG | WNOWAIT);
392 if (useconds < 1000000) useconds <<= 1;
393 if ((read_timeout != -1 && useconds / 1000 > read_timeout) ||
394 (TimeIsOut(start_time, total_timeout))) {
400 if (child_info.si_code == CLD_KILLED) {
404 "Child killed by signal %d",
405 child_info.si_status);
409 if (child_info.si_code == CLD_EXITED && child_info.si_status != 0) {
413 "Child exited with status %d",
414 child_info.si_status);
419 #else // No waitid call.
422 waitpid(pid, &child_status, 0);
423 child_waiter.ChildIsDeadNow();
424 if (WIFSIGNALED(child_status)) {
428 "Child killed by signal %d",
429 WTERMSIG(child_status));
433 if (WEXITSTATUS(child_status) != 0) {
435 int exit_status = WEXITSTATUS(child_status);
438 "Child exited with status %d",
444 #endif // No waitid call.
453 int read_timeout = -1;
454 int total_timeout = -1;
455 if (!GetTimeouts(args, &read_timeout, &total_timeout))
return v8::Undefined();
458 if (!args[1]->IsArray()) {
472 struct timeval start_time;
473 gettimeofday(&start_time,
NULL);
476 if (!exec_args.
Init(args[0], command_args)) {
479 int exec_error_fds[2];
482 if (pipe(exec_error_fds) != 0) {
485 if (pipe(stdout_fds) != 0) {
491 ExecSubprocess(exec_error_fds, stdout_fds, exec_args);
497 close(exec_error_fds[kWriteFD]);
498 close(stdout_fds[kWriteFD]);
499 OpenFDCloser error_read_closer(exec_error_fds[kReadFD]);
502 if (!ChildLaunchedOK(exec_error_fds))
return v8::Undefined();
513 if (!WaitForChild(pid,
521 return scope.
Close(accumulator);
527 const char* message =
"chdir() takes one argument";
531 if (*directory ==
NULL) {
532 const char* message =
"os.chdir(): String conversion of argument failed.";
535 if (chdir(*directory) != 0) {
544 const char* message =
"umask() takes one argument";
547 if (args[0]->IsNumber()) {
548 mode_t mask = args[0]->Int32Value();
549 int previous = umask(mask);
552 const char* message =
"umask() argument must be numeric";
558 static bool CheckItsADirectory(
char* directory) {
559 struct stat stat_buf;
560 int stat_result = stat(directory, &stat_buf);
561 if (stat_result != 0) {
565 if ((stat_buf.st_mode & S_IFDIR) != 0)
return true;
573 static bool mkdirp(
char* directory, mode_t mask) {
574 int result = mkdir(directory, mask);
575 if (result == 0)
return true;
576 if (errno == EEXIST) {
577 return CheckItsADirectory(directory);
578 }
else if (errno == ENOENT) {
579 char* last_slash = strrchr(directory,
'/');
580 if (last_slash ==
NULL) {
585 if (!mkdirp(directory, mask))
return false;
587 result = mkdir(directory, mask);
588 if (result == 0)
return true;
589 if (errno == EEXIST) {
590 return CheckItsADirectory(directory);
604 if (args[1]->IsNumber()) {
605 mask = args[1]->Int32Value();
607 const char* message =
"mkdirp() second argument must be numeric";
610 }
else if (args.
Length() != 1) {
611 const char* message =
"mkdirp() takes one or two arguments";
615 if (*directory ==
NULL) {
616 const char* message =
"os.mkdirp(): String conversion of argument failed.";
619 mkdirp(*directory, mask);
626 const char* message =
"rmdir() takes one or two arguments";
630 if (*directory ==
NULL) {
631 const char* message =
"os.rmdir(): String conversion of argument failed.";
641 const char* message =
"setenv() takes two arguments";
647 const char* message =
648 "os.setenv(): String conversion of variable name failed.";
651 if (*value ==
NULL) {
652 const char* message =
653 "os.setenv(): String conversion of variable contents failed.";
656 setenv(*var, *value, 1);
663 const char* message =
"unsetenv() takes one argument";
668 const char* message =
669 "os.setenv(): String conversion of variable name failed.";
static Local< FunctionTemplate > New(InvocationCallback callback=0, Handle< Value > data=Handle< Value >(), Handle< Signature > signature=Handle< Signature >())
bool Init(Handle< Value > arg0, Handle< Array > command_args)
static V8EXPORT Local< String > New(const char *data, int length=-1)
static Handle< Value > SetUMask(const Arguments &args)
static void AddOSMethods(Handle< ObjectTemplate > os_template)
static Handle< T > Cast(Handle< S > that)
void Set(Handle< String > name, Handle< Data > value, PropertyAttribute attributes=None)
static Handle< Value > SetEnvironment(const Arguments &args)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
static Handle< Value > RemoveDirectory(const Arguments &args)
static V8EXPORT v8::Local< v8::String > Empty()
static Handle< Value > UnsetEnvironment(const Arguments &args)
static V8EXPORT Local< Integer > New(int32_t value)
Local< T > Close(Handle< T > value)
Handle< Primitive > V8EXPORT Undefined()
static V8EXPORT Local< Number > New(double value)
static V8EXPORT Local< String > Concat(Handle< String > left, Handle< String > right)
static Handle< Value > MakeDirectory(const Arguments &args)
Handle< Value > V8EXPORT ThrowException(Handle< Value > exception)
static Handle< Value > System(const Arguments &args)
static Handle< Value > ChangeDirectory(const Arguments &args)
static V8EXPORT Local< Object > New()
static const unsigned kMaxArgs