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 |