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 |