Index: runtime/bin/process_linux.cc |
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc |
index 2431f0f61652516f78125c52843a4f7439c6e027..03d0bb73e292e38372b782f75a9d3c039f9a5b13 100644 |
--- a/runtime/bin/process_linux.cc |
+++ b/runtime/bin/process_linux.cc |
@@ -18,6 +18,7 @@ |
#include <unistd.h> // NOLINT |
#include "bin/dartutils.h" |
+#include "bin/directory.h" |
#include "bin/fdutils.h" |
#include "bin/file.h" |
#include "bin/lockers.h" |
@@ -243,7 +244,8 @@ Monitor* ExitCodeHandler::monitor_ = new Monitor(); |
class ProcessStarter { |
public: |
- ProcessStarter(const char* path, |
+ ProcessStarter(Namespace* namespc, |
+ const char* path, |
char* arguments[], |
intptr_t arguments_length, |
const char* working_directory, |
@@ -256,7 +258,8 @@ class ProcessStarter { |
intptr_t* id, |
intptr_t* exit_event, |
char** os_error_message) |
- : path_(path), |
+ : namespc_(namespc), |
+ path_(path), |
working_directory_(working_directory), |
mode_(mode), |
in_(in), |
@@ -432,6 +435,25 @@ class ProcessStarter { |
} |
} |
+ // If fexecve() should be used to launch the program, returns the fd to use |
+ // in fd and returns true. If execvp should be used, returns false. If there |
+ // was an error that should be reported to the caller, sets fd to -1 and |
+ // returns true. |
+ bool ShouldUseFexecve(int* pathfd) { |
+ ASSERT(pathfd != NULL); |
+ NamespaceScope ns(namespc_, path_); |
+ const intptr_t fd = |
+ TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_RDONLY)); |
+ if ((fd == -1) && (errno == ENOENT)) { |
+ if (strchr(path_, '/') == NULL) { |
+ // There wasn't in the namespace and contained no '/'. Punt to execvp. |
+ return false; |
+ } |
+ } |
+ *pathfd = fd; |
+ return true; |
+ } |
+ |
void ExecProcess() { |
if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
ReportChildError(); |
@@ -446,7 +468,7 @@ class ProcessStarter { |
} |
if (working_directory_ != NULL && |
- TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
+ !Directory::SetCurrent(namespc_, working_directory_)) { |
ReportChildError(); |
} |
@@ -454,8 +476,17 @@ class ProcessStarter { |
environ = program_environment_; |
} |
- VOID_TEMP_FAILURE_RETRY( |
- execvp(path_, const_cast<char* const*>(program_arguments_))); |
+ int pathfd; |
+ if (ShouldUseFexecve(&pathfd)) { |
+ if (pathfd == -1) { |
+ ReportChildError(); |
+ } |
+ VOID_TEMP_FAILURE_RETRY(fexecve( |
+ pathfd, const_cast<char* const*>(program_arguments_), environ)); |
+ } else { |
+ VOID_TEMP_FAILURE_RETRY( |
+ execvp(path_, const_cast<char* const*>(program_arguments_))); |
+ } |
ReportChildError(); |
} |
@@ -497,22 +528,31 @@ class ProcessStarter { |
} |
if ((working_directory_ != NULL) && |
- (TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1)) { |
+ !Directory::SetCurrent(namespc_, working_directory_)) { |
ReportChildError(); |
} |
// Report the final PID and do the exec. |
ReportPid(getpid()); // getpid cannot fail. |
- VOID_TEMP_FAILURE_RETRY( |
- execvp(path_, const_cast<char* const*>(program_arguments_))); |
+ int pathfd; |
+ if (ShouldUseFexecve(&pathfd)) { |
+ if (pathfd == -1) { |
+ ReportChildError(); |
+ } |
+ VOID_TEMP_FAILURE_RETRY(fexecve( |
+ pathfd, const_cast<char* const*>(program_arguments_), environ)); |
+ } else { |
+ VOID_TEMP_FAILURE_RETRY( |
+ execvp(path_, const_cast<char* const*>(program_arguments_))); |
+ } |
ReportChildError(); |
} else { |
- // Exit the intermeiate process. |
+ // Exit the intermediate process. |
exit(0); |
} |
} |
} else { |
- // Exit the intermeiate process. |
+ // Exit the intermediate process. |
exit(0); |
} |
} |
@@ -717,6 +757,7 @@ class ProcessStarter { |
char** program_arguments_; |
char** program_environment_; |
+ Namespace* namespc_; |
const char* path_; |
const char* working_directory_; |
ProcessStartMode mode_; |
@@ -731,7 +772,8 @@ class ProcessStarter { |
DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); |
}; |
-int Process::Start(const char* path, |
+int Process::Start(Namespace* namespc, |
+ const char* path, |
char* arguments[], |
intptr_t arguments_length, |
const char* working_directory, |
@@ -744,9 +786,9 @@ int Process::Start(const char* path, |
intptr_t* id, |
intptr_t* exit_event, |
char** os_error_message) { |
- ProcessStarter starter(path, arguments, arguments_length, working_directory, |
- environment, environment_length, mode, in, out, err, |
- id, exit_event, os_error_message); |
+ ProcessStarter starter(namespc, path, arguments, arguments_length, |
+ working_directory, environment, environment_length, |
+ mode, in, out, err, id, exit_event, os_error_message); |
return starter.Start(); |
} |