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

Side by Side 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, 2 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/native_support/process_impl.h"
6
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <unistd.h>
10
11 #include <algorithm>
12 #include <limits>
13 #include <utility>
14 #include <vector>
15
16 #include "base/command_line.h"
17 #include "base/environment.h"
18 #include "base/files/scoped_file.h"
19 #include "base/logging.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/process/launch.h"
22 #include "base/process/process.h"
23 #include "build/build_config.h"
24 #include "mojo/services/files/public/interfaces/types.mojom.h"
25 #include "services/native_support/make_pty_pair.h"
26 #include "services/native_support/process_controller_impl.h"
27 #include "services/native_support/process_io_redirection.h"
28
29 namespace native_support {
30
31 namespace {
32
33 class SetsidPreExecDelegate : public base::LaunchOptions::PreExecDelegate {
34 public:
35 SetsidPreExecDelegate() {}
36 ~SetsidPreExecDelegate() override {}
37
38 void RunAsyncSafe() override {
39 static const char kErrorMessage[] = "setsid() failed";
40
41 // Note: |setsid()| and |write()| are both async-signal-safe.
42 if (setsid() == static_cast<pid_t>(-1))
43 write(STDERR_FILENO, kErrorMessage, sizeof(kErrorMessage) - 1);
44 }
45
46 private:
47 DISALLOW_COPY_AND_ASSIGN(SetsidPreExecDelegate);
48 };
49
50 } // namespace
51
52 ProcessImpl::ProcessImpl(scoped_refptr<base::TaskRunner> worker_runner,
53 mojo::ApplicationConnection* connection,
54 mojo::InterfaceRequest<Process> request)
55 : worker_runner_(worker_runner.Pass()), binding_(this, request.Pass()) {}
56
57 ProcessImpl::~ProcessImpl() {}
58
59 void ProcessImpl::Spawn(
60 const mojo::String& path,
61 mojo::Array<mojo::String> argv,
62 mojo::Array<mojo::String> envp,
63 mojo::files::FilePtr stdin_file,
64 mojo::files::FilePtr stdout_file,
65 mojo::files::FilePtr stderr_file,
66 mojo::InterfaceRequest<ProcessController> process_controller,
67 const SpawnCallback& callback) {
68 std::vector<int> fds_to_inherit(3, -1);
69
70 // stdin:
71 base::ScopedFD stdin_fd;
72 base::ScopedFD stdin_parent_fd;
73 if (stdin_file) {
74 int stdin_pipe_fds[2] = {-1, -1};
75 CHECK_EQ(pipe(stdin_pipe_fds), 0);
76 stdin_fd.reset(stdin_pipe_fds[0]);
77 stdin_parent_fd.reset(stdin_pipe_fds[1]);
78 } else {
79 stdin_fd.reset(HANDLE_EINTR(open("/dev/null", O_RDONLY)));
80 }
81 fds_to_inherit[STDIN_FILENO] = stdin_fd.get();
82
83 // stdout:
84 base::ScopedFD stdout_fd;
85 base::ScopedFD stdout_parent_fd;
86 if (stdout_file) {
87 int stdout_pipe_fds[2] = {-1, -1};
88 CHECK_EQ(pipe(stdout_pipe_fds), 0);
89 stdout_fd.reset(stdout_pipe_fds[1]);
90 stdout_parent_fd.reset(stdout_pipe_fds[0]);
91 } else {
92 stdout_fd.reset(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
93 }
94 fds_to_inherit[STDOUT_FILENO] = stdout_fd.get();
95
96 // stderr:
97 base::ScopedFD stderr_fd;
98 base::ScopedFD stderr_parent_fd;
99 if (stderr_file) {
100 int stderr_pipe_fds[2] = {-1, -1};
101 CHECK_EQ(pipe(stderr_pipe_fds), 0);
102 stderr_fd.reset(stderr_pipe_fds[1]);
103 stderr_parent_fd.reset(stderr_pipe_fds[0]);
104 } else {
105 stderr_fd.reset(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
106 }
107 fds_to_inherit[STDERR_FILENO] = stderr_fd.get();
108
109 std::unique_ptr<ProcessIORedirection> process_io_redirection(
110 new ProcessIORedirectionForStdIO(
111 stdin_file.Pass(), stdout_file.Pass(), stderr_file.Pass(),
112 stdin_parent_fd.Pass(), stdout_parent_fd.Pass(),
113 stderr_parent_fd.Pass()));
114
115 SpawnImpl(path, argv.Pass(), envp.Pass(), std::move(process_io_redirection),
116 fds_to_inherit, process_controller.Pass(), callback);
117 }
118
119 void ProcessImpl::SpawnWithTerminal(
120 const mojo::String& path,
121 mojo::Array<mojo::String> argv,
122 mojo::Array<mojo::String> envp,
123 mojo::files::FilePtr terminal_file,
124 mojo::InterfaceRequest<ProcessController> process_controller,
125 const SpawnWithTerminalCallback& callback) {
126 DCHECK(terminal_file);
127
128 std::vector<int> fds_to_inherit(3, -1);
129
130 base::ScopedFD master_fd;
131 base::ScopedFD slave_fd;
132 int errno_value = 0;
133 if (!MakePtyPair(&master_fd, &slave_fd, &errno_value)) {
134 // TODO(vtl): Well, this is dumb (we should use errno_value).
135 callback.Run(mojo::files::ERROR_UNKNOWN);
136 return;
137 }
138
139 // stdin:
140 base::ScopedFD stdin_fd(slave_fd.Pass());
141 fds_to_inherit[STDIN_FILENO] = stdin_fd.get();
142
143 // stdout:
144 base::ScopedFD stdout_fd(HANDLE_EINTR(dup(stdin_fd.get())));
145 fds_to_inherit[STDOUT_FILENO] = stdout_fd.get();
146
147 // stderr:
148 base::ScopedFD stderr_fd(HANDLE_EINTR(dup(stdin_fd.get())));
149 fds_to_inherit[STDERR_FILENO] = stderr_fd.get();
150
151 std::unique_ptr<ProcessIORedirection> process_io_redirection(
152 new ProcessIORedirectionForTerminal(terminal_file.Pass(),
153 master_fd.Pass()));
154
155 SpawnImpl(path, argv.Pass(), envp.Pass(), std::move(process_io_redirection),
156 fds_to_inherit, process_controller.Pass(), callback);
157 }
158
159 void ProcessImpl::SpawnImpl(
160 const mojo::String& path,
161 mojo::Array<mojo::String> argv,
162 mojo::Array<mojo::String> envp,
163 std::unique_ptr<ProcessIORedirection> process_io_redirection,
164 const std::vector<int>& fds_to_inherit,
165 mojo::InterfaceRequest<ProcessController> process_controller,
166 const SpawnCallback& callback) {
167 DCHECK(!path.is_null());
168 DCHECK(process_controller.is_pending());
169
170 size_t argc = std::max(argv.size(), static_cast<size_t>(1));
171 std::vector<const char*> argv_ptrs(argc);
172 if (argv.is_null()) {
173 argv_ptrs[0] = path.data();
174 } else {
175 if (!argv.size() ||
176 argv.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
177 callback.Run(mojo::files::ERROR_INVALID_ARGUMENT);
178 return;
179 }
180 // TODO(vtl): Currently, we don't support setting argv[0], due to
181 // |base::CommandLine| limitations.
182 argv_ptrs[0] = path.data();
183 for (size_t i = 1; i < argv.size(); i++)
184 argv_ptrs[i] = argv[i].data();
185 }
186 base::CommandLine command_line(static_cast<int>(argc), argv_ptrs.data());
187
188 bool inherit_environment = true;
189 base::EnvironmentMap environment_map;
190 if (!envp.is_null()) {
191 inherit_environment = false;
192 for (size_t i = 0; i < envp.size(); i++) {
193 std::string s(envp[i].data());
194 size_t equals_pos = s.find_first_of('=');
195 environment_map[s.substr(0, equals_pos)] =
196 (equals_pos == std::string::npos) ? std::string()
197 : s.substr(equals_pos + 1);
198 }
199 }
200
201 base::FileHandleMappingVector fd_mapping;
202 DCHECK(fds_to_inherit.size() >= 3);
203 for (size_t i = 0; i < fds_to_inherit.size(); i++) {
204 DCHECK_GE(fds_to_inherit[i], 0);
205 fd_mapping.push_back(
206 std::make_pair(fds_to_inherit[i], static_cast<int>(i)));
207 }
208
209 SetsidPreExecDelegate pre_exec_delegate;
210 base::LaunchOptions launch_options;
211 launch_options.wait = false;
212 launch_options.environ.swap(environment_map);
213 launch_options.clear_environ = !inherit_environment;
214 launch_options.fds_to_remap = &fd_mapping;
215 // launch_options.maximize_rlimits
216 launch_options.new_process_group = false;
217 // launch_options.clone_flags = 0;
218 #if defined(OS_LINUX)
219 launch_options.allow_new_privs = true;
220 #endif
221 // launch_options.kill_on_parent_death = true;
222 // launch_options.current_directory
223 launch_options.pre_exec_delegate = &pre_exec_delegate;
224
225 base::Process process = LaunchProcess(command_line, launch_options);
226 // Note: Failure is extremely unusual. E.g., it won't fail even if |path|
227 // doesn't exist (since fork succeeds; it's the exec that fails).
228 if (!process.IsValid()) {
229 // TODO(vtl): Well, this is dumb (can we check errno?).
230 callback.Run(mojo::files::ERROR_UNKNOWN);
231 return;
232 }
233
234 new ProcessControllerImpl(worker_runner_, process_controller.Pass(),
235 process.Pass(), std::move(process_io_redirection));
236 callback.Run(mojo::files::ERROR_OK);
237 }
238
239 } // namespace native_support
OLDNEW
« 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