| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 static const unsigned kMaxArgs = 1000; | 231 static const unsigned kMaxArgs = 1000; |
| 232 char** arg_array() { return exec_args_; } | 232 char** arg_array() { return exec_args_; } |
| 233 char* arg0() { return exec_args_[0]; } | 233 char* arg0() { return exec_args_[0]; } |
| 234 | 234 |
| 235 private: | 235 private: |
| 236 char* exec_args_[kMaxArgs + 1]; | 236 char* exec_args_[kMaxArgs + 1]; |
| 237 }; | 237 }; |
| 238 | 238 |
| 239 | 239 |
| 240 // Gets the optional timeouts from the arguments to the system() call. | 240 // Gets the optional timeouts from the arguments to the system() call. |
| 241 static bool GetTimeouts(const Arguments& args, | 241 static bool GetTimeouts(const v8::FunctionCallbackInfo<v8::Value>& args, |
| 242 int* read_timeout, | 242 int* read_timeout, |
| 243 int* total_timeout) { | 243 int* total_timeout) { |
| 244 if (args.Length() > 3) { | 244 if (args.Length() > 3) { |
| 245 if (args[3]->IsNumber()) { | 245 if (args[3]->IsNumber()) { |
| 246 *total_timeout = args[3]->Int32Value(); | 246 *total_timeout = args[3]->Int32Value(); |
| 247 } else { | 247 } else { |
| 248 ThrowException(String::New("system: Argument 4 must be a number")); | 248 ThrowException(String::New("system: Argument 4 must be a number")); |
| 249 return false; | 249 return false; |
| 250 } | 250 } |
| 251 } | 251 } |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 return false; | 441 return false; |
| 442 } | 442 } |
| 443 | 443 |
| 444 #endif // No waitid call. | 444 #endif // No waitid call. |
| 445 | 445 |
| 446 return true; | 446 return true; |
| 447 } | 447 } |
| 448 | 448 |
| 449 | 449 |
| 450 // Implementation of the system() function (see d8.h for details). | 450 // Implementation of the system() function (see d8.h for details). |
| 451 Handle<Value> Shell::System(const Arguments& args) { | 451 void Shell::System(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 452 HandleScope scope(args.GetIsolate()); | 452 HandleScope scope(args.GetIsolate()); |
| 453 int read_timeout = -1; | 453 int read_timeout = -1; |
| 454 int total_timeout = -1; | 454 int total_timeout = -1; |
| 455 if (!GetTimeouts(args, &read_timeout, &total_timeout)) return v8::Undefined(); | 455 if (!GetTimeouts(args, &read_timeout, &total_timeout)) return; |
| 456 Handle<Array> command_args; | 456 Handle<Array> command_args; |
| 457 if (args.Length() > 1) { | 457 if (args.Length() > 1) { |
| 458 if (!args[1]->IsArray()) { | 458 if (!args[1]->IsArray()) { |
| 459 return ThrowException(String::New("system: Argument 2 must be an array")); | 459 ThrowException(String::New("system: Argument 2 must be an array")); |
| 460 return; |
| 460 } | 461 } |
| 461 command_args = Handle<Array>::Cast(args[1]); | 462 command_args = Handle<Array>::Cast(args[1]); |
| 462 } else { | 463 } else { |
| 463 command_args = Array::New(0); | 464 command_args = Array::New(0); |
| 464 } | 465 } |
| 465 if (command_args->Length() > ExecArgs::kMaxArgs) { | 466 if (command_args->Length() > ExecArgs::kMaxArgs) { |
| 466 return ThrowException(String::New("Too many arguments to system()")); | 467 ThrowException(String::New("Too many arguments to system()")); |
| 468 return; |
| 467 } | 469 } |
| 468 if (args.Length() < 1) { | 470 if (args.Length() < 1) { |
| 469 return ThrowException(String::New("Too few arguments to system()")); | 471 ThrowException(String::New("Too few arguments to system()")); |
| 472 return; |
| 470 } | 473 } |
| 471 | 474 |
| 472 struct timeval start_time; | 475 struct timeval start_time; |
| 473 gettimeofday(&start_time, NULL); | 476 gettimeofday(&start_time, NULL); |
| 474 | 477 |
| 475 ExecArgs exec_args; | 478 ExecArgs exec_args; |
| 476 if (!exec_args.Init(args[0], command_args)) { | 479 if (!exec_args.Init(args[0], command_args)) { |
| 477 return v8::Undefined(); | 480 return; |
| 478 } | 481 } |
| 479 int exec_error_fds[2]; | 482 int exec_error_fds[2]; |
| 480 int stdout_fds[2]; | 483 int stdout_fds[2]; |
| 481 | 484 |
| 482 if (pipe(exec_error_fds) != 0) { | 485 if (pipe(exec_error_fds) != 0) { |
| 483 return ThrowException(String::New("pipe syscall failed.")); | 486 ThrowException(String::New("pipe syscall failed.")); |
| 487 return; |
| 484 } | 488 } |
| 485 if (pipe(stdout_fds) != 0) { | 489 if (pipe(stdout_fds) != 0) { |
| 486 return ThrowException(String::New("pipe syscall failed.")); | 490 ThrowException(String::New("pipe syscall failed.")); |
| 491 return; |
| 487 } | 492 } |
| 488 | 493 |
| 489 pid_t pid = fork(); | 494 pid_t pid = fork(); |
| 490 if (pid == 0) { // Child process. | 495 if (pid == 0) { // Child process. |
| 491 ExecSubprocess(exec_error_fds, stdout_fds, exec_args); | 496 ExecSubprocess(exec_error_fds, stdout_fds, exec_args); |
| 492 exit(1); | 497 exit(1); |
| 493 } | 498 } |
| 494 | 499 |
| 495 // Parent process. Ensure that we clean up if we exit this function early. | 500 // Parent process. Ensure that we clean up if we exit this function early. |
| 496 ZombieProtector child_waiter(pid); | 501 ZombieProtector child_waiter(pid); |
| 497 close(exec_error_fds[kWriteFD]); | 502 close(exec_error_fds[kWriteFD]); |
| 498 close(stdout_fds[kWriteFD]); | 503 close(stdout_fds[kWriteFD]); |
| 499 OpenFDCloser error_read_closer(exec_error_fds[kReadFD]); | 504 OpenFDCloser error_read_closer(exec_error_fds[kReadFD]); |
| 500 OpenFDCloser stdout_read_closer(stdout_fds[kReadFD]); | 505 OpenFDCloser stdout_read_closer(stdout_fds[kReadFD]); |
| 501 | 506 |
| 502 if (!ChildLaunchedOK(exec_error_fds)) return v8::Undefined(); | 507 if (!ChildLaunchedOK(exec_error_fds)) return; |
| 503 | 508 |
| 504 Handle<Value> accumulator = GetStdout(stdout_fds[kReadFD], | 509 Handle<Value> accumulator = GetStdout(stdout_fds[kReadFD], |
| 505 start_time, | 510 start_time, |
| 506 read_timeout, | 511 read_timeout, |
| 507 total_timeout); | 512 total_timeout); |
| 508 if (accumulator->IsUndefined()) { | 513 if (accumulator->IsUndefined()) { |
| 509 kill(pid, SIGINT); // On timeout, kill the subprocess. | 514 kill(pid, SIGINT); // On timeout, kill the subprocess. |
| 510 return accumulator; | 515 args.GetReturnValue().Set(accumulator); |
| 516 return; |
| 511 } | 517 } |
| 512 | 518 |
| 513 if (!WaitForChild(pid, | 519 if (!WaitForChild(pid, |
| 514 child_waiter, | 520 child_waiter, |
| 515 start_time, | 521 start_time, |
| 516 read_timeout, | 522 read_timeout, |
| 517 total_timeout)) { | 523 total_timeout)) { |
| 518 return v8::Undefined(); | 524 return; |
| 519 } | 525 } |
| 520 | 526 |
| 521 return scope.Close(accumulator); | 527 args.GetReturnValue().Set(accumulator); |
| 522 } | 528 } |
| 523 | 529 |
| 524 | 530 |
| 525 Handle<Value> Shell::ChangeDirectory(const Arguments& args) { | 531 void Shell::ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 526 if (args.Length() != 1) { | 532 if (args.Length() != 1) { |
| 527 const char* message = "chdir() takes one argument"; | 533 const char* message = "chdir() takes one argument"; |
| 528 return ThrowException(String::New(message)); | 534 ThrowException(String::New(message)); |
| 535 return; |
| 529 } | 536 } |
| 530 String::Utf8Value directory(args[0]); | 537 String::Utf8Value directory(args[0]); |
| 531 if (*directory == NULL) { | 538 if (*directory == NULL) { |
| 532 const char* message = "os.chdir(): String conversion of argument failed."; | 539 const char* message = "os.chdir(): String conversion of argument failed."; |
| 533 return ThrowException(String::New(message)); | 540 ThrowException(String::New(message)); |
| 541 return; |
| 534 } | 542 } |
| 535 if (chdir(*directory) != 0) { | 543 if (chdir(*directory) != 0) { |
| 536 return ThrowException(String::New(strerror(errno))); | 544 ThrowException(String::New(strerror(errno))); |
| 545 return; |
| 537 } | 546 } |
| 538 return v8::Undefined(); | |
| 539 } | 547 } |
| 540 | 548 |
| 541 | 549 |
| 542 Handle<Value> Shell::SetUMask(const Arguments& args) { | 550 void Shell::SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 543 if (args.Length() != 1) { | 551 if (args.Length() != 1) { |
| 544 const char* message = "umask() takes one argument"; | 552 const char* message = "umask() takes one argument"; |
| 545 return ThrowException(String::New(message)); | 553 ThrowException(String::New(message)); |
| 554 return; |
| 546 } | 555 } |
| 547 if (args[0]->IsNumber()) { | 556 if (args[0]->IsNumber()) { |
| 548 mode_t mask = args[0]->Int32Value(); | 557 mode_t mask = args[0]->Int32Value(); |
| 549 int previous = umask(mask); | 558 int previous = umask(mask); |
| 550 return Number::New(previous); | 559 args.GetReturnValue().Set(previous); |
| 560 return; |
| 551 } else { | 561 } else { |
| 552 const char* message = "umask() argument must be numeric"; | 562 const char* message = "umask() argument must be numeric"; |
| 553 return ThrowException(String::New(message)); | 563 ThrowException(String::New(message)); |
| 564 return; |
| 554 } | 565 } |
| 555 } | 566 } |
| 556 | 567 |
| 557 | 568 |
| 558 static bool CheckItsADirectory(char* directory) { | 569 static bool CheckItsADirectory(char* directory) { |
| 559 struct stat stat_buf; | 570 struct stat stat_buf; |
| 560 int stat_result = stat(directory, &stat_buf); | 571 int stat_result = stat(directory, &stat_buf); |
| 561 if (stat_result != 0) { | 572 if (stat_result != 0) { |
| 562 ThrowException(String::New(strerror(errno))); | 573 ThrowException(String::New(strerror(errno))); |
| 563 return false; | 574 return false; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 591 } | 602 } |
| 592 ThrowException(String::New(strerror(errno))); | 603 ThrowException(String::New(strerror(errno))); |
| 593 return false; | 604 return false; |
| 594 } else { | 605 } else { |
| 595 ThrowException(String::New(strerror(errno))); | 606 ThrowException(String::New(strerror(errno))); |
| 596 return false; | 607 return false; |
| 597 } | 608 } |
| 598 } | 609 } |
| 599 | 610 |
| 600 | 611 |
| 601 Handle<Value> Shell::MakeDirectory(const Arguments& args) { | 612 void Shell::MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 602 mode_t mask = 0777; | 613 mode_t mask = 0777; |
| 603 if (args.Length() == 2) { | 614 if (args.Length() == 2) { |
| 604 if (args[1]->IsNumber()) { | 615 if (args[1]->IsNumber()) { |
| 605 mask = args[1]->Int32Value(); | 616 mask = args[1]->Int32Value(); |
| 606 } else { | 617 } else { |
| 607 const char* message = "mkdirp() second argument must be numeric"; | 618 const char* message = "mkdirp() second argument must be numeric"; |
| 608 return ThrowException(String::New(message)); | 619 ThrowException(String::New(message)); |
| 620 return; |
| 609 } | 621 } |
| 610 } else if (args.Length() != 1) { | 622 } else if (args.Length() != 1) { |
| 611 const char* message = "mkdirp() takes one or two arguments"; | 623 const char* message = "mkdirp() takes one or two arguments"; |
| 612 return ThrowException(String::New(message)); | 624 ThrowException(String::New(message)); |
| 625 return; |
| 613 } | 626 } |
| 614 String::Utf8Value directory(args[0]); | 627 String::Utf8Value directory(args[0]); |
| 615 if (*directory == NULL) { | 628 if (*directory == NULL) { |
| 616 const char* message = "os.mkdirp(): String conversion of argument failed."; | 629 const char* message = "os.mkdirp(): String conversion of argument failed."; |
| 617 return ThrowException(String::New(message)); | 630 ThrowException(String::New(message)); |
| 631 return; |
| 618 } | 632 } |
| 619 mkdirp(*directory, mask); | 633 mkdirp(*directory, mask); |
| 620 return v8::Undefined(); | |
| 621 } | 634 } |
| 622 | 635 |
| 623 | 636 |
| 624 Handle<Value> Shell::RemoveDirectory(const Arguments& args) { | 637 void Shell::RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 625 if (args.Length() != 1) { | 638 if (args.Length() != 1) { |
| 626 const char* message = "rmdir() takes one or two arguments"; | 639 const char* message = "rmdir() takes one or two arguments"; |
| 627 return ThrowException(String::New(message)); | 640 ThrowException(String::New(message)); |
| 641 return; |
| 628 } | 642 } |
| 629 String::Utf8Value directory(args[0]); | 643 String::Utf8Value directory(args[0]); |
| 630 if (*directory == NULL) { | 644 if (*directory == NULL) { |
| 631 const char* message = "os.rmdir(): String conversion of argument failed."; | 645 const char* message = "os.rmdir(): String conversion of argument failed."; |
| 632 return ThrowException(String::New(message)); | 646 ThrowException(String::New(message)); |
| 647 return; |
| 633 } | 648 } |
| 634 rmdir(*directory); | 649 rmdir(*directory); |
| 635 return v8::Undefined(); | |
| 636 } | 650 } |
| 637 | 651 |
| 638 | 652 |
| 639 Handle<Value> Shell::SetEnvironment(const Arguments& args) { | 653 void Shell::SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 640 if (args.Length() != 2) { | 654 if (args.Length() != 2) { |
| 641 const char* message = "setenv() takes two arguments"; | 655 const char* message = "setenv() takes two arguments"; |
| 642 return ThrowException(String::New(message)); | 656 ThrowException(String::New(message)); |
| 657 return; |
| 643 } | 658 } |
| 644 String::Utf8Value var(args[0]); | 659 String::Utf8Value var(args[0]); |
| 645 String::Utf8Value value(args[1]); | 660 String::Utf8Value value(args[1]); |
| 646 if (*var == NULL) { | 661 if (*var == NULL) { |
| 647 const char* message = | 662 const char* message = |
| 648 "os.setenv(): String conversion of variable name failed."; | 663 "os.setenv(): String conversion of variable name failed."; |
| 649 return ThrowException(String::New(message)); | 664 ThrowException(String::New(message)); |
| 665 return; |
| 650 } | 666 } |
| 651 if (*value == NULL) { | 667 if (*value == NULL) { |
| 652 const char* message = | 668 const char* message = |
| 653 "os.setenv(): String conversion of variable contents failed."; | 669 "os.setenv(): String conversion of variable contents failed."; |
| 654 return ThrowException(String::New(message)); | 670 ThrowException(String::New(message)); |
| 671 return; |
| 655 } | 672 } |
| 656 setenv(*var, *value, 1); | 673 setenv(*var, *value, 1); |
| 657 return v8::Undefined(); | |
| 658 } | 674 } |
| 659 | 675 |
| 660 | 676 |
| 661 Handle<Value> Shell::UnsetEnvironment(const Arguments& args) { | 677 void Shell::UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 662 if (args.Length() != 1) { | 678 if (args.Length() != 1) { |
| 663 const char* message = "unsetenv() takes one argument"; | 679 const char* message = "unsetenv() takes one argument"; |
| 664 return ThrowException(String::New(message)); | 680 ThrowException(String::New(message)); |
| 681 return; |
| 665 } | 682 } |
| 666 String::Utf8Value var(args[0]); | 683 String::Utf8Value var(args[0]); |
| 667 if (*var == NULL) { | 684 if (*var == NULL) { |
| 668 const char* message = | 685 const char* message = |
| 669 "os.setenv(): String conversion of variable name failed."; | 686 "os.setenv(): String conversion of variable name failed."; |
| 670 return ThrowException(String::New(message)); | 687 ThrowException(String::New(message)); |
| 688 return; |
| 671 } | 689 } |
| 672 unsetenv(*var); | 690 unsetenv(*var); |
| 673 return v8::Undefined(); | |
| 674 } | 691 } |
| 675 | 692 |
| 676 | 693 |
| 677 void Shell::AddOSMethods(Handle<ObjectTemplate> os_templ) { | 694 void Shell::AddOSMethods(Handle<ObjectTemplate> os_templ) { |
| 678 os_templ->Set(String::New("system"), FunctionTemplate::New(System)); | 695 os_templ->Set(String::New("system"), FunctionTemplate::New(System)); |
| 679 os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory)); | 696 os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory)); |
| 680 os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment)); | 697 os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment)); |
| 681 os_templ->Set(String::New("unsetenv"), | 698 os_templ->Set(String::New("unsetenv"), |
| 682 FunctionTemplate::New(UnsetEnvironment)); | 699 FunctionTemplate::New(UnsetEnvironment)); |
| 683 os_templ->Set(String::New("umask"), FunctionTemplate::New(SetUMask)); | 700 os_templ->Set(String::New("umask"), FunctionTemplate::New(SetUMask)); |
| 684 os_templ->Set(String::New("mkdirp"), FunctionTemplate::New(MakeDirectory)); | 701 os_templ->Set(String::New("mkdirp"), FunctionTemplate::New(MakeDirectory)); |
| 685 os_templ->Set(String::New("rmdir"), FunctionTemplate::New(RemoveDirectory)); | 702 os_templ->Set(String::New("rmdir"), FunctionTemplate::New(RemoveDirectory)); |
| 686 } | 703 } |
| 687 | 704 |
| 688 } // namespace v8 | 705 } // namespace v8 |
| OLD | NEW |