| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
| 6 #if defined(HOST_OS_LINUX) | 6 #if defined(HOST_OS_LINUX) |
| 7 | 7 |
| 8 #include "bin/process.h" | 8 #include "bin/process.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| 11 #include <fcntl.h> // NOLINT | 11 #include <fcntl.h> // NOLINT |
| 12 #include <poll.h> // NOLINT | 12 #include <poll.h> // NOLINT |
| 13 #include <stdio.h> // NOLINT | 13 #include <stdio.h> // NOLINT |
| 14 #include <stdlib.h> // NOLINT | 14 #include <stdlib.h> // NOLINT |
| 15 #include <string.h> // NOLINT | 15 #include <string.h> // NOLINT |
| 16 #include <sys/resource.h> // NOLINT | 16 #include <sys/resource.h> // NOLINT |
| 17 #include <sys/wait.h> // NOLINT | 17 #include <sys/wait.h> // NOLINT |
| 18 #include <unistd.h> // NOLINT | 18 #include <unistd.h> // NOLINT |
| 19 | 19 |
| 20 #include "bin/dartutils.h" | 20 #include "bin/dartutils.h" |
| 21 #include "bin/directory.h" |
| 21 #include "bin/fdutils.h" | 22 #include "bin/fdutils.h" |
| 22 #include "bin/file.h" | 23 #include "bin/file.h" |
| 23 #include "bin/lockers.h" | 24 #include "bin/lockers.h" |
| 24 #include "bin/log.h" | 25 #include "bin/log.h" |
| 25 #include "bin/reference_counting.h" | 26 #include "bin/reference_counting.h" |
| 26 #include "bin/thread.h" | 27 #include "bin/thread.h" |
| 27 | 28 |
| 28 #include "platform/signal_blocker.h" | 29 #include "platform/signal_blocker.h" |
| 29 #include "platform/utils.h" | 30 #include "platform/utils.h" |
| 30 | 31 |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); | 237 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); |
| 237 }; | 238 }; |
| 238 | 239 |
| 239 bool ExitCodeHandler::running_ = false; | 240 bool ExitCodeHandler::running_ = false; |
| 240 int ExitCodeHandler::process_count_ = 0; | 241 int ExitCodeHandler::process_count_ = 0; |
| 241 bool ExitCodeHandler::terminate_done_ = false; | 242 bool ExitCodeHandler::terminate_done_ = false; |
| 242 Monitor* ExitCodeHandler::monitor_ = new Monitor(); | 243 Monitor* ExitCodeHandler::monitor_ = new Monitor(); |
| 243 | 244 |
| 244 class ProcessStarter { | 245 class ProcessStarter { |
| 245 public: | 246 public: |
| 246 ProcessStarter(const char* path, | 247 ProcessStarter(Namespace* namespc, |
| 248 const char* path, |
| 247 char* arguments[], | 249 char* arguments[], |
| 248 intptr_t arguments_length, | 250 intptr_t arguments_length, |
| 249 const char* working_directory, | 251 const char* working_directory, |
| 250 char* environment[], | 252 char* environment[], |
| 251 intptr_t environment_length, | 253 intptr_t environment_length, |
| 252 ProcessStartMode mode, | 254 ProcessStartMode mode, |
| 253 intptr_t* in, | 255 intptr_t* in, |
| 254 intptr_t* out, | 256 intptr_t* out, |
| 255 intptr_t* err, | 257 intptr_t* err, |
| 256 intptr_t* id, | 258 intptr_t* id, |
| 257 intptr_t* exit_event, | 259 intptr_t* exit_event, |
| 258 char** os_error_message) | 260 char** os_error_message) |
| 259 : path_(path), | 261 : namespc_(namespc), |
| 262 path_(path), |
| 260 working_directory_(working_directory), | 263 working_directory_(working_directory), |
| 261 mode_(mode), | 264 mode_(mode), |
| 262 in_(in), | 265 in_(in), |
| 263 out_(out), | 266 out_(out), |
| 264 err_(err), | 267 err_(err), |
| 265 id_(id), | 268 id_(id), |
| 266 exit_event_(exit_event), | 269 exit_event_(exit_event), |
| 267 os_error_message_(os_error_message) { | 270 os_error_message_(os_error_message) { |
| 268 read_in_[0] = -1; | 271 read_in_[0] = -1; |
| 269 read_in_[1] = -1; | 272 read_in_[1] = -1; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 perror("Failed receiving notification message"); | 428 perror("Failed receiving notification message"); |
| 426 exit(1); | 429 exit(1); |
| 427 } | 430 } |
| 428 if (mode_ == kNormal) { | 431 if (mode_ == kNormal) { |
| 429 ExecProcess(); | 432 ExecProcess(); |
| 430 } else { | 433 } else { |
| 431 ExecDetachedProcess(); | 434 ExecDetachedProcess(); |
| 432 } | 435 } |
| 433 } | 436 } |
| 434 | 437 |
| 438 // If fexecve() should be used to launch the program, returns the fd to use |
| 439 // in fd and returns true. If execvp should be used, returns false. If there |
| 440 // was an error that should be reported to the caller, sets fd to -1 and |
| 441 // returns true. |
| 442 bool ShouldUseFexecve(int* pathfd) { |
| 443 ASSERT(pathfd != NULL); |
| 444 NamespaceScope ns(namespc_, path_); |
| 445 const intptr_t fd = |
| 446 TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_RDONLY)); |
| 447 if ((fd == -1) && (errno == ENOENT)) { |
| 448 if (strchr(path_, '/') == NULL) { |
| 449 // There wasn't in the namespace and contained no '/'. Punt to execvp. |
| 450 return false; |
| 451 } |
| 452 } |
| 453 *pathfd = fd; |
| 454 return true; |
| 455 } |
| 456 |
| 435 void ExecProcess() { | 457 void ExecProcess() { |
| 436 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { | 458 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 437 ReportChildError(); | 459 ReportChildError(); |
| 438 } | 460 } |
| 439 | 461 |
| 440 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { | 462 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 441 ReportChildError(); | 463 ReportChildError(); |
| 442 } | 464 } |
| 443 | 465 |
| 444 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 466 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 445 ReportChildError(); | 467 ReportChildError(); |
| 446 } | 468 } |
| 447 | 469 |
| 448 if (working_directory_ != NULL && | 470 if (working_directory_ != NULL && |
| 449 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { | 471 !Directory::SetCurrent(namespc_, working_directory_)) { |
| 450 ReportChildError(); | 472 ReportChildError(); |
| 451 } | 473 } |
| 452 | 474 |
| 453 if (program_environment_ != NULL) { | 475 if (program_environment_ != NULL) { |
| 454 environ = program_environment_; | 476 environ = program_environment_; |
| 455 } | 477 } |
| 456 | 478 |
| 457 VOID_TEMP_FAILURE_RETRY( | 479 int pathfd; |
| 458 execvp(path_, const_cast<char* const*>(program_arguments_))); | 480 if (ShouldUseFexecve(&pathfd)) { |
| 481 if (pathfd == -1) { |
| 482 ReportChildError(); |
| 483 } |
| 484 VOID_TEMP_FAILURE_RETRY(fexecve( |
| 485 pathfd, const_cast<char* const*>(program_arguments_), environ)); |
| 486 } else { |
| 487 VOID_TEMP_FAILURE_RETRY( |
| 488 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 489 } |
| 459 | 490 |
| 460 ReportChildError(); | 491 ReportChildError(); |
| 461 } | 492 } |
| 462 | 493 |
| 463 void ExecDetachedProcess() { | 494 void ExecDetachedProcess() { |
| 464 if (mode_ == kDetached) { | 495 if (mode_ == kDetached) { |
| 465 ASSERT(write_out_[0] == -1); | 496 ASSERT(write_out_[0] == -1); |
| 466 ASSERT(write_out_[1] == -1); | 497 ASSERT(write_out_[1] == -1); |
| 467 ASSERT(read_err_[0] == -1); | 498 ASSERT(read_err_[0] == -1); |
| 468 ASSERT(read_err_[1] == -1); | 499 ASSERT(read_err_[1] == -1); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 490 if (pid < 0) { | 521 if (pid < 0) { |
| 491 ReportChildError(); | 522 ReportChildError(); |
| 492 } else if (pid == 0) { | 523 } else if (pid == 0) { |
| 493 if (mode_ == kDetached) { | 524 if (mode_ == kDetached) { |
| 494 SetupDetached(); | 525 SetupDetached(); |
| 495 } else { | 526 } else { |
| 496 SetupDetachedWithStdio(); | 527 SetupDetachedWithStdio(); |
| 497 } | 528 } |
| 498 | 529 |
| 499 if ((working_directory_ != NULL) && | 530 if ((working_directory_ != NULL) && |
| 500 (TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1)) { | 531 !Directory::SetCurrent(namespc_, working_directory_)) { |
| 501 ReportChildError(); | 532 ReportChildError(); |
| 502 } | 533 } |
| 503 | 534 |
| 504 // Report the final PID and do the exec. | 535 // Report the final PID and do the exec. |
| 505 ReportPid(getpid()); // getpid cannot fail. | 536 ReportPid(getpid()); // getpid cannot fail. |
| 506 VOID_TEMP_FAILURE_RETRY( | 537 int pathfd; |
| 507 execvp(path_, const_cast<char* const*>(program_arguments_))); | 538 if (ShouldUseFexecve(&pathfd)) { |
| 539 if (pathfd == -1) { |
| 540 ReportChildError(); |
| 541 } |
| 542 VOID_TEMP_FAILURE_RETRY(fexecve( |
| 543 pathfd, const_cast<char* const*>(program_arguments_), environ)); |
| 544 } else { |
| 545 VOID_TEMP_FAILURE_RETRY( |
| 546 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 547 } |
| 508 ReportChildError(); | 548 ReportChildError(); |
| 509 } else { | 549 } else { |
| 510 // Exit the intermeiate process. | 550 // Exit the intermediate process. |
| 511 exit(0); | 551 exit(0); |
| 512 } | 552 } |
| 513 } | 553 } |
| 514 } else { | 554 } else { |
| 515 // Exit the intermeiate process. | 555 // Exit the intermediate process. |
| 516 exit(0); | 556 exit(0); |
| 517 } | 557 } |
| 518 } | 558 } |
| 519 | 559 |
| 520 int RegisterProcess(pid_t pid) { | 560 int RegisterProcess(pid_t pid) { |
| 521 int result; | 561 int result; |
| 522 int event_fds[2]; | 562 int event_fds[2]; |
| 523 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); | 563 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); |
| 524 if (result < 0) { | 564 if (result < 0) { |
| 525 return CleanupAndReturnError(); | 565 return CleanupAndReturnError(); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 } | 750 } |
| 711 | 751 |
| 712 int read_in_[2]; // Pipe for stdout to child process. | 752 int read_in_[2]; // Pipe for stdout to child process. |
| 713 int read_err_[2]; // Pipe for stderr to child process. | 753 int read_err_[2]; // Pipe for stderr to child process. |
| 714 int write_out_[2]; // Pipe for stdin to child process. | 754 int write_out_[2]; // Pipe for stdin to child process. |
| 715 int exec_control_[2]; // Pipe to get the result from exec. | 755 int exec_control_[2]; // Pipe to get the result from exec. |
| 716 | 756 |
| 717 char** program_arguments_; | 757 char** program_arguments_; |
| 718 char** program_environment_; | 758 char** program_environment_; |
| 719 | 759 |
| 760 Namespace* namespc_; |
| 720 const char* path_; | 761 const char* path_; |
| 721 const char* working_directory_; | 762 const char* working_directory_; |
| 722 ProcessStartMode mode_; | 763 ProcessStartMode mode_; |
| 723 intptr_t* in_; | 764 intptr_t* in_; |
| 724 intptr_t* out_; | 765 intptr_t* out_; |
| 725 intptr_t* err_; | 766 intptr_t* err_; |
| 726 intptr_t* id_; | 767 intptr_t* id_; |
| 727 intptr_t* exit_event_; | 768 intptr_t* exit_event_; |
| 728 char** os_error_message_; | 769 char** os_error_message_; |
| 729 | 770 |
| 730 DISALLOW_ALLOCATION(); | 771 DISALLOW_ALLOCATION(); |
| 731 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); | 772 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); |
| 732 }; | 773 }; |
| 733 | 774 |
| 734 int Process::Start(const char* path, | 775 int Process::Start(Namespace* namespc, |
| 776 const char* path, |
| 735 char* arguments[], | 777 char* arguments[], |
| 736 intptr_t arguments_length, | 778 intptr_t arguments_length, |
| 737 const char* working_directory, | 779 const char* working_directory, |
| 738 char* environment[], | 780 char* environment[], |
| 739 intptr_t environment_length, | 781 intptr_t environment_length, |
| 740 ProcessStartMode mode, | 782 ProcessStartMode mode, |
| 741 intptr_t* in, | 783 intptr_t* in, |
| 742 intptr_t* out, | 784 intptr_t* out, |
| 743 intptr_t* err, | 785 intptr_t* err, |
| 744 intptr_t* id, | 786 intptr_t* id, |
| 745 intptr_t* exit_event, | 787 intptr_t* exit_event, |
| 746 char** os_error_message) { | 788 char** os_error_message) { |
| 747 ProcessStarter starter(path, arguments, arguments_length, working_directory, | 789 ProcessStarter starter(namespc, path, arguments, arguments_length, |
| 748 environment, environment_length, mode, in, out, err, | 790 working_directory, environment, environment_length, |
| 749 id, exit_event, os_error_message); | 791 mode, in, out, err, id, exit_event, os_error_message); |
| 750 return starter.Start(); | 792 return starter.Start(); |
| 751 } | 793 } |
| 752 | 794 |
| 753 static bool CloseProcessBuffers(struct pollfd fds[3]) { | 795 static bool CloseProcessBuffers(struct pollfd fds[3]) { |
| 754 int e = errno; | 796 int e = errno; |
| 755 VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); | 797 VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); |
| 756 VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); | 798 VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); |
| 757 VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); | 799 VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); |
| 758 errno = e; | 800 errno = e; |
| 759 return false; | 801 return false; |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 995 bzero(&act, sizeof(act)); | 1037 bzero(&act, sizeof(act)); |
| 996 act.sa_handler = SIG_DFL; | 1038 act.sa_handler = SIG_DFL; |
| 997 sigaction(signal, &act, NULL); | 1039 sigaction(signal, &act, NULL); |
| 998 } | 1040 } |
| 999 } | 1041 } |
| 1000 | 1042 |
| 1001 } // namespace bin | 1043 } // namespace bin |
| 1002 } // namespace dart | 1044 } // namespace dart |
| 1003 | 1045 |
| 1004 #endif // defined(HOST_OS_LINUX) | 1046 #endif // defined(HOST_OS_LINUX) |
| OLD | NEW |