Chromium Code Reviews| 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 11 matching lines...) Expand all Loading... | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 | 28 |
| 29 #include <stdlib.h> | 29 #include <stdlib.h> |
| 30 #include <errno.h> | 30 #include <errno.h> |
| 31 #include <sys/types.h> | 31 #include <sys/types.h> |
| 32 #include <sys/stat.h> | |
| 32 #include <sys/time.h> | 33 #include <sys/time.h> |
| 33 #include <time.h> | 34 #include <time.h> |
| 34 #include <unistd.h> | 35 #include <unistd.h> |
| 35 #include <fcntl.h> | 36 #include <fcntl.h> |
| 36 #include <sys/wait.h> | 37 #include <sys/wait.h> |
| 37 #include <signal.h> | 38 #include <signal.h> |
| 38 | 39 |
| 39 | 40 |
| 40 #include "d8.h" | 41 #include "d8.h" |
| 41 #include "d8-debug.h" | 42 #include "d8-debug.h" |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 return false; | 156 return false; |
| 156 } | 157 } |
| 157 | 158 |
| 158 | 159 |
| 159 // A utility class that does a non-hanging waitpid on the child process if we | 160 // A utility class that does a non-hanging waitpid on the child process if we |
| 160 // bail out of the System() function early. If you don't ever do a waitpid on | 161 // bail out of the System() function early. If you don't ever do a waitpid on |
| 161 // a subprocess then it turns into one of those annoying 'zombie processes'. | 162 // a subprocess then it turns into one of those annoying 'zombie processes'. |
| 162 class ZombieProtector { | 163 class ZombieProtector { |
| 163 public: | 164 public: |
| 164 explicit ZombieProtector(int pid): pid_(pid) { } | 165 explicit ZombieProtector(int pid): pid_(pid) { } |
| 165 ~ZombieProtector() { if (pid_ != 0) waitpid(pid_, NULL, WNOHANG); } | 166 ~ZombieProtector() { if (pid_ != 0) waitpid(pid_, NULL, 0); } |
| 166 void ChildIsDeadNow() { pid_ = 0; } | 167 void ChildIsDeadNow() { pid_ = 0; } |
| 167 private: | 168 private: |
| 168 int pid_; | 169 int pid_; |
| 169 }; | 170 }; |
| 170 | 171 |
| 171 | 172 |
| 172 // A utility class that closes a file descriptor when it goes out of scope. | 173 // A utility class that closes a file descriptor when it goes out of scope. |
| 173 class OpenFDCloser { | 174 class OpenFDCloser { |
| 174 public: | 175 public: |
| 175 explicit OpenFDCloser(int fd): fd_(fd) { } | 176 explicit OpenFDCloser(int fd): fd_(fd) { } |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 waitid(P_PID, pid, &child_info, WEXITED | WNOHANG | WNOWAIT); | 388 waitid(P_PID, pid, &child_info, WEXITED | WNOHANG | WNOWAIT); |
| 388 usleep(useconds); | 389 usleep(useconds); |
| 389 if (useconds < 1000000) useconds <<= 1; | 390 if (useconds < 1000000) useconds <<= 1; |
| 390 if ((read_timeout != -1 && useconds / 1000 > read_timeout) || | 391 if ((read_timeout != -1 && useconds / 1000 > read_timeout) || |
| 391 (TimeIsOut(start_time, total_timeout))) { | 392 (TimeIsOut(start_time, total_timeout))) { |
| 392 ThrowException(String::New("Timed out waiting for process to terminate")); | 393 ThrowException(String::New("Timed out waiting for process to terminate")); |
| 393 kill(pid, SIGINT); | 394 kill(pid, SIGINT); |
| 394 return false; | 395 return false; |
| 395 } | 396 } |
| 396 } | 397 } |
| 397 child_waiter.ChildIsDeadNow(); | |
| 398 if (child_info.si_code == CLD_KILLED) { | 398 if (child_info.si_code == CLD_KILLED) { |
| 399 char message[999]; | 399 char message[999]; |
| 400 snprintf(message, | 400 snprintf(message, |
| 401 sizeof(message), | 401 sizeof(message), |
| 402 "Child killed by signal %d", | 402 "Child killed by signal %d", |
| 403 child_info.si_status); | 403 child_info.si_status); |
| 404 ThrowException(String::New(message)); | 404 ThrowException(String::New(message)); |
| 405 return false; | 405 return false; |
| 406 } | 406 } |
| 407 if (child_info.si_code == CLD_EXITED && child_info.si_status != 0) { | 407 if (child_info.si_code == CLD_EXITED && child_info.si_status != 0) { |
| 408 char message[999]; | 408 char message[999]; |
| 409 snprintf(message, | 409 snprintf(message, |
| 410 sizeof(message), | 410 sizeof(message), |
| 411 "Child exited with status %d", | 411 "Child exited with status %d", |
| 412 child_info.si_status); | 412 child_info.si_status); |
| 413 ThrowException(String::New(message)); | 413 ThrowException(String::New(message)); |
| 414 return false; | 414 return false; |
| 415 } | 415 } |
| 416 | 416 |
| 417 #else // No waitid call. | 417 #else // No waitid call. |
| 418 | 418 |
| 419 int child_status; | 419 int child_status; |
| 420 printf("waitpid"); | |
| 421 waitpid(pid, &child_status, 0); // We hang here if the child doesn't exit. | 420 waitpid(pid, &child_status, 0); // We hang here if the child doesn't exit. |
| 422 child_waiter.ChildIsDeadNow(); | 421 child_waiter.ChildIsDeadNow(); |
| 423 if (WIFSIGNALED(child_status)) { | 422 if (WIFSIGNALED(child_status)) { |
| 424 char message[999]; | 423 char message[999]; |
| 425 snprintf(message, | 424 snprintf(message, |
| 426 sizeof(message), | 425 sizeof(message), |
| 427 "Child killed by signal %d", | 426 "Child killed by signal %d", |
| 428 WTERMSIG(child_status)); | 427 WTERMSIG(child_status)); |
| 429 ThrowException(String::New(message)); | 428 ThrowException(String::New(message)); |
| 430 return false; | 429 return false; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 const char* message = "os.chdir(): String conversion of argument failed."; | 530 const char* message = "os.chdir(): String conversion of argument failed."; |
| 532 return ThrowException(String::New(message)); | 531 return ThrowException(String::New(message)); |
| 533 } | 532 } |
| 534 if (chdir(*directory) != 0) { | 533 if (chdir(*directory) != 0) { |
| 535 return ThrowException(String::New(strerror(errno))); | 534 return ThrowException(String::New(strerror(errno))); |
| 536 } | 535 } |
| 537 return v8::Undefined(); | 536 return v8::Undefined(); |
| 538 } | 537 } |
| 539 | 538 |
| 540 | 539 |
| 540 Handle<Value> Shell::SetUMask(const Arguments& args) { | |
| 541 if (args.Length() != 1) { | |
| 542 const char* message = "umask() takes one argument"; | |
| 543 return ThrowException(String::New(message)); | |
| 544 } | |
| 545 if (args[0]->IsNumber()) { | |
| 546 mode_t mask = args[0]->Int32Value(); | |
| 547 int previous = umask(mask); | |
| 548 return Number::New(previous); | |
| 549 } else { | |
| 550 const char* message = "umask() argument must be numeric"; | |
| 551 return ThrowException(String::New(message)); | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 | |
| 556 static bool CheckItsADirectory(char* directory) { | |
| 557 struct stat stat_buf; | |
| 558 int stat_result = stat(directory, &stat_buf); | |
| 559 if (stat_result != 0) { | |
| 560 ThrowException(String::New(strerror(errno))); | |
| 561 return false; | |
| 562 } | |
| 563 if ((stat_buf.st_mode & S_IFDIR) != 0) return true; | |
| 564 ThrowException(String::New(strerror(EEXIST))); | |
| 565 return false; | |
| 566 } | |
| 567 | |
| 568 | |
| 569 // Returns true for success. Creates intermediate directories as needed. No | |
| 570 // error if the directory exists already. | |
| 571 static bool mkdirp(char* directory, mode_t mask) { | |
| 572 int result = mkdir(directory, mask); | |
| 573 if (result == 0) return true; | |
| 574 if (errno == EEXIST) { | |
| 575 return CheckItsADirectory(directory); | |
| 576 } else if (errno == ENOENT) { // Intermediate path element is missing. | |
| 577 char* last_slash = strrchr(directory, '/'); | |
| 578 if (last_slash == NULL) { | |
| 579 ThrowException(String::New(strerror(errno))); | |
| 580 return false; | |
| 581 } | |
| 582 *last_slash = 0; | |
| 583 if (!mkdirp(directory, mask)) return false; | |
| 584 *last_slash = '/'; | |
| 585 result = mkdir(directory, mask); | |
| 586 if (result == 0) return true; | |
| 587 if (errno == EEXIST) { | |
|
Søren Thygesen Gjesse
2009/03/31 12:28:02
Is this is to handle from paths with '..' e.g. xxx
Erik Corry
2009/03/31 12:36:31
Can I just pretend that's what I was thinking abou
| |
| 588 return CheckItsADirectory(directory); | |
| 589 } | |
| 590 ThrowException(String::New(strerror(errno))); | |
| 591 return false; | |
| 592 } else { | |
| 593 ThrowException(String::New(strerror(errno))); | |
| 594 return false; | |
| 595 } | |
| 596 } | |
| 597 | |
| 598 | |
| 599 Handle<Value> Shell::MakeDirectory(const Arguments& args) { | |
| 600 mode_t mask = 0777; | |
| 601 if (args.Length() == 2) { | |
| 602 if (args[1]->IsNumber()) { | |
| 603 mask = args[1]->Int32Value(); | |
| 604 } else { | |
| 605 const char* message = "mkdirp() second argument must be numeric"; | |
| 606 return ThrowException(String::New(message)); | |
| 607 } | |
| 608 } else if (args.Length() != 1) { | |
| 609 const char* message = "mkdirp() takes one or two arguments"; | |
| 610 return ThrowException(String::New(message)); | |
| 611 } | |
| 612 String::Utf8Value directory(args[0]); | |
| 613 if (*directory == NULL) { | |
| 614 const char* message = "os.mkdirp(): String conversion of argument failed."; | |
| 615 return ThrowException(String::New(message)); | |
| 616 } | |
| 617 mkdirp(*directory, mask); | |
| 618 return v8::Undefined(); | |
| 619 } | |
| 620 | |
| 621 | |
| 622 Handle<Value> Shell::RemoveDirectory(const Arguments& args) { | |
| 623 if (args.Length() != 1) { | |
| 624 const char* message = "rmdir() takes one or two arguments"; | |
| 625 return ThrowException(String::New(message)); | |
| 626 } | |
| 627 String::Utf8Value directory(args[0]); | |
| 628 if (*directory == NULL) { | |
| 629 const char* message = "os.rmdir(): String conversion of argument failed."; | |
| 630 return ThrowException(String::New(message)); | |
| 631 } | |
| 632 rmdir(*directory); | |
| 633 return v8::Undefined(); | |
| 634 } | |
| 635 | |
| 636 | |
| 541 Handle<Value> Shell::SetEnvironment(const Arguments& args) { | 637 Handle<Value> Shell::SetEnvironment(const Arguments& args) { |
| 542 if (args.Length() != 2) { | 638 if (args.Length() != 2) { |
| 543 const char* message = "setenv() takes two arguments"; | 639 const char* message = "setenv() takes two arguments"; |
| 544 return ThrowException(String::New(message)); | 640 return ThrowException(String::New(message)); |
| 545 } | 641 } |
| 546 String::Utf8Value var(args[0]); | 642 String::Utf8Value var(args[0]); |
| 547 String::Utf8Value value(args[1]); | 643 String::Utf8Value value(args[1]); |
| 548 if (*var == NULL) { | 644 if (*var == NULL) { |
| 549 const char* message = | 645 const char* message = |
| 550 "os.setenv(): String conversion of variable name failed."; | 646 "os.setenv(): String conversion of variable name failed."; |
| 551 return ThrowException(String::New(message)); | 647 return ThrowException(String::New(message)); |
| 552 } | 648 } |
| 553 if (*value == NULL) { | 649 if (*value == NULL) { |
| 554 const char* message = | 650 const char* message = |
| 555 "os.setenv(): String conversion of variable contents failed."; | 651 "os.setenv(): String conversion of variable contents failed."; |
| 556 return ThrowException(String::New(message)); | 652 return ThrowException(String::New(message)); |
| 557 } | 653 } |
| 558 setenv(*var, *value, 1); | 654 setenv(*var, *value, 1); |
| 559 return v8::Undefined(); | 655 return v8::Undefined(); |
| 560 } | 656 } |
| 561 | 657 |
| 562 | 658 |
| 659 void Shell::AddOSMethods(Handle<ObjectTemplate> os_templ) { | |
| 660 os_templ->Set(String::New("system"), FunctionTemplate::New(System)); | |
| 661 os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory)); | |
| 662 os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment)); | |
| 663 os_templ->Set(String::New("umask"), FunctionTemplate::New(SetUMask)); | |
| 664 os_templ->Set(String::New("mkdirp"), FunctionTemplate::New(MakeDirectory)); | |
| 665 os_templ->Set(String::New("rmdir"), FunctionTemplate::New(RemoveDirectory)); | |
| 666 } | |
| 667 | |
| 563 } // namespace v8 | 668 } // namespace v8 |
| OLD | NEW |