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 |