Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1468)

Unified Diff: services/native_support/process_impl.cc

Issue 1321253010: Add a "native_support" service. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: fix android? Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « services/native_support/process_impl.h ('k') | services/native_support/process_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: services/native_support/process_impl.cc
diff --git a/services/native_support/process_impl.cc b/services/native_support/process_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2fc77ffdc79a95571e2bd66f2cee3305308800c1
--- /dev/null
+++ b/services/native_support/process_impl.cc
@@ -0,0 +1,239 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/native_support/process_impl.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "build/build_config.h"
+#include "mojo/services/files/public/interfaces/types.mojom.h"
+#include "services/native_support/make_pty_pair.h"
+#include "services/native_support/process_controller_impl.h"
+#include "services/native_support/process_io_redirection.h"
+
+namespace native_support {
+
+namespace {
+
+class SetsidPreExecDelegate : public base::LaunchOptions::PreExecDelegate {
+ public:
+ SetsidPreExecDelegate() {}
+ ~SetsidPreExecDelegate() override {}
+
+ void RunAsyncSafe() override {
+ static const char kErrorMessage[] = "setsid() failed";
+
+ // Note: |setsid()| and |write()| are both async-signal-safe.
+ if (setsid() == static_cast<pid_t>(-1))
+ write(STDERR_FILENO, kErrorMessage, sizeof(kErrorMessage) - 1);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SetsidPreExecDelegate);
+};
+
+} // namespace
+
+ProcessImpl::ProcessImpl(scoped_refptr<base::TaskRunner> worker_runner,
+ mojo::ApplicationConnection* connection,
+ mojo::InterfaceRequest<Process> request)
+ : worker_runner_(worker_runner.Pass()), binding_(this, request.Pass()) {}
+
+ProcessImpl::~ProcessImpl() {}
+
+void ProcessImpl::Spawn(
+ const mojo::String& path,
+ mojo::Array<mojo::String> argv,
+ mojo::Array<mojo::String> envp,
+ mojo::files::FilePtr stdin_file,
+ mojo::files::FilePtr stdout_file,
+ mojo::files::FilePtr stderr_file,
+ mojo::InterfaceRequest<ProcessController> process_controller,
+ const SpawnCallback& callback) {
+ std::vector<int> fds_to_inherit(3, -1);
+
+ // stdin:
+ base::ScopedFD stdin_fd;
+ base::ScopedFD stdin_parent_fd;
+ if (stdin_file) {
+ int stdin_pipe_fds[2] = {-1, -1};
+ CHECK_EQ(pipe(stdin_pipe_fds), 0);
+ stdin_fd.reset(stdin_pipe_fds[0]);
+ stdin_parent_fd.reset(stdin_pipe_fds[1]);
+ } else {
+ stdin_fd.reset(HANDLE_EINTR(open("/dev/null", O_RDONLY)));
+ }
+ fds_to_inherit[STDIN_FILENO] = stdin_fd.get();
+
+ // stdout:
+ base::ScopedFD stdout_fd;
+ base::ScopedFD stdout_parent_fd;
+ if (stdout_file) {
+ int stdout_pipe_fds[2] = {-1, -1};
+ CHECK_EQ(pipe(stdout_pipe_fds), 0);
+ stdout_fd.reset(stdout_pipe_fds[1]);
+ stdout_parent_fd.reset(stdout_pipe_fds[0]);
+ } else {
+ stdout_fd.reset(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
+ }
+ fds_to_inherit[STDOUT_FILENO] = stdout_fd.get();
+
+ // stderr:
+ base::ScopedFD stderr_fd;
+ base::ScopedFD stderr_parent_fd;
+ if (stderr_file) {
+ int stderr_pipe_fds[2] = {-1, -1};
+ CHECK_EQ(pipe(stderr_pipe_fds), 0);
+ stderr_fd.reset(stderr_pipe_fds[1]);
+ stderr_parent_fd.reset(stderr_pipe_fds[0]);
+ } else {
+ stderr_fd.reset(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
+ }
+ fds_to_inherit[STDERR_FILENO] = stderr_fd.get();
+
+ std::unique_ptr<ProcessIORedirection> process_io_redirection(
+ new ProcessIORedirectionForStdIO(
+ stdin_file.Pass(), stdout_file.Pass(), stderr_file.Pass(),
+ stdin_parent_fd.Pass(), stdout_parent_fd.Pass(),
+ stderr_parent_fd.Pass()));
+
+ SpawnImpl(path, argv.Pass(), envp.Pass(), std::move(process_io_redirection),
+ fds_to_inherit, process_controller.Pass(), callback);
+}
+
+void ProcessImpl::SpawnWithTerminal(
+ const mojo::String& path,
+ mojo::Array<mojo::String> argv,
+ mojo::Array<mojo::String> envp,
+ mojo::files::FilePtr terminal_file,
+ mojo::InterfaceRequest<ProcessController> process_controller,
+ const SpawnWithTerminalCallback& callback) {
+ DCHECK(terminal_file);
+
+ std::vector<int> fds_to_inherit(3, -1);
+
+ base::ScopedFD master_fd;
+ base::ScopedFD slave_fd;
+ int errno_value = 0;
+ if (!MakePtyPair(&master_fd, &slave_fd, &errno_value)) {
+ // TODO(vtl): Well, this is dumb (we should use errno_value).
+ callback.Run(mojo::files::ERROR_UNKNOWN);
+ return;
+ }
+
+ // stdin:
+ base::ScopedFD stdin_fd(slave_fd.Pass());
+ fds_to_inherit[STDIN_FILENO] = stdin_fd.get();
+
+ // stdout:
+ base::ScopedFD stdout_fd(HANDLE_EINTR(dup(stdin_fd.get())));
+ fds_to_inherit[STDOUT_FILENO] = stdout_fd.get();
+
+ // stderr:
+ base::ScopedFD stderr_fd(HANDLE_EINTR(dup(stdin_fd.get())));
+ fds_to_inherit[STDERR_FILENO] = stderr_fd.get();
+
+ std::unique_ptr<ProcessIORedirection> process_io_redirection(
+ new ProcessIORedirectionForTerminal(terminal_file.Pass(),
+ master_fd.Pass()));
+
+ SpawnImpl(path, argv.Pass(), envp.Pass(), std::move(process_io_redirection),
+ fds_to_inherit, process_controller.Pass(), callback);
+}
+
+void ProcessImpl::SpawnImpl(
+ const mojo::String& path,
+ mojo::Array<mojo::String> argv,
+ mojo::Array<mojo::String> envp,
+ std::unique_ptr<ProcessIORedirection> process_io_redirection,
+ const std::vector<int>& fds_to_inherit,
+ mojo::InterfaceRequest<ProcessController> process_controller,
+ const SpawnCallback& callback) {
+ DCHECK(!path.is_null());
+ DCHECK(process_controller.is_pending());
+
+ size_t argc = std::max(argv.size(), static_cast<size_t>(1));
+ std::vector<const char*> argv_ptrs(argc);
+ if (argv.is_null()) {
+ argv_ptrs[0] = path.data();
+ } else {
+ if (!argv.size() ||
+ argv.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
+ callback.Run(mojo::files::ERROR_INVALID_ARGUMENT);
+ return;
+ }
+ // TODO(vtl): Currently, we don't support setting argv[0], due to
+ // |base::CommandLine| limitations.
+ argv_ptrs[0] = path.data();
+ for (size_t i = 1; i < argv.size(); i++)
+ argv_ptrs[i] = argv[i].data();
+ }
+ base::CommandLine command_line(static_cast<int>(argc), argv_ptrs.data());
+
+ bool inherit_environment = true;
+ base::EnvironmentMap environment_map;
+ if (!envp.is_null()) {
+ inherit_environment = false;
+ for (size_t i = 0; i < envp.size(); i++) {
+ std::string s(envp[i].data());
+ size_t equals_pos = s.find_first_of('=');
+ environment_map[s.substr(0, equals_pos)] =
+ (equals_pos == std::string::npos) ? std::string()
+ : s.substr(equals_pos + 1);
+ }
+ }
+
+ base::FileHandleMappingVector fd_mapping;
+ DCHECK(fds_to_inherit.size() >= 3);
+ for (size_t i = 0; i < fds_to_inherit.size(); i++) {
+ DCHECK_GE(fds_to_inherit[i], 0);
+ fd_mapping.push_back(
+ std::make_pair(fds_to_inherit[i], static_cast<int>(i)));
+ }
+
+ SetsidPreExecDelegate pre_exec_delegate;
+ base::LaunchOptions launch_options;
+ launch_options.wait = false;
+ launch_options.environ.swap(environment_map);
+ launch_options.clear_environ = !inherit_environment;
+ launch_options.fds_to_remap = &fd_mapping;
+ // launch_options.maximize_rlimits
+ launch_options.new_process_group = false;
+ // launch_options.clone_flags = 0;
+#if defined(OS_LINUX)
+ launch_options.allow_new_privs = true;
+#endif
+ // launch_options.kill_on_parent_death = true;
+ // launch_options.current_directory
+ launch_options.pre_exec_delegate = &pre_exec_delegate;
+
+ base::Process process = LaunchProcess(command_line, launch_options);
+ // Note: Failure is extremely unusual. E.g., it won't fail even if |path|
+ // doesn't exist (since fork succeeds; it's the exec that fails).
+ if (!process.IsValid()) {
+ // TODO(vtl): Well, this is dumb (can we check errno?).
+ callback.Run(mojo::files::ERROR_UNKNOWN);
+ return;
+ }
+
+ new ProcessControllerImpl(worker_runner_, process_controller.Pass(),
+ process.Pass(), std::move(process_io_redirection));
+ callback.Run(mojo::files::ERROR_OK);
+}
+
+} // namespace native_support
« no previous file with comments | « services/native_support/process_impl.h ('k') | services/native_support/process_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698