blob: 0e1fbbddf8cd3d78e5bab57f3d1d3a743abef777 [file] [log] [blame]
Primiano Tucci6d7d2542020-03-17 20:03:48 +00001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/ext/base/subprocess.h"
18
Primiano Tucci1797cd12020-04-14 09:43:24 +010019#if PERFETTO_HAS_SUBPROCESS()
20
Primiano Tucci6d7d2542020-03-17 20:03:48 +000021#include <poll.h>
22#include <signal.h>
23#include <stdio.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26#include <unistd.h>
27
28#include <algorithm>
29#include <thread>
Primiano Tuccie1a28482020-08-06 14:43:54 +020030#include <tuple>
Primiano Tucci6d7d2542020-03-17 20:03:48 +000031
32#include "perfetto/base/build_config.h"
33#include "perfetto/base/logging.h"
34#include "perfetto/base/time.h"
35#include "perfetto/ext/base/utils.h"
36
37#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
38 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
39#include <sys/prctl.h>
40#endif
41
42// In MacOS this is not defined in any header.
43extern "C" char** environ;
44
45namespace perfetto {
46namespace base {
47
48namespace {
49
50struct ChildProcessArgs {
51 Subprocess::Args* create_args;
52 const char* exec_cmd = nullptr;
53 std::vector<char*> argv;
54 std::vector<char*> env;
55 int stdin_pipe_rd = -1;
56 int stdouterr_pipe_wr = -1;
57};
58
59// Don't add any dynamic allocation in this function. This will be invoked
60// under a fork(), potentially in a state where the allocator lock is held.
61void __attribute__((noreturn)) ChildProcess(ChildProcessArgs* args) {
62#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
63 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
64 // In no case we want a child process to outlive its parent process. This is
65 // relevant for tests, so that a test failure/crash doesn't leave child
66 // processes around that get reparented to init.
67 prctl(PR_SET_PDEATHSIG, SIGKILL);
68#endif
69
70 auto die = [args](const char* err) __attribute__((noreturn)) {
71 base::ignore_result(write(args->stdouterr_pipe_wr, err, strlen(err)));
72 base::ignore_result(write(args->stdouterr_pipe_wr, "\n", 1));
73 // From https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
74 // "In particular, the value 128 is used to indicate failure to execute
75 // another program in a subprocess. This convention is not universally
76 // obeyed, but it is a good idea to follow it in your programs."
77 _exit(128);
78 };
79
80 auto set_fd_close_on_exec = [&die](int fd, bool close_on_exec) {
81 int flags = fcntl(fd, F_GETFD, 0);
82 if (flags < 0)
83 die("fcntl(F_GETFD) failed");
84 flags = close_on_exec ? (flags | FD_CLOEXEC) : (flags & ~FD_CLOEXEC);
85 if (fcntl(fd, F_SETFD, flags) < 0)
86 die("fcntl(F_SETFD) failed");
87 };
88
89 if (getppid() == 1)
90 die("terminating because parent process died");
91
92 if (dup2(args->stdin_pipe_rd, STDIN_FILENO) == -1)
93 die("Failed to dup2(STDIN)");
94 close(args->stdin_pipe_rd);
95
96 switch (args->create_args->stdout_mode) {
97 case Subprocess::kInherit:
98 break;
99 case Subprocess::kDevNull: {
100 if (dup2(open("/dev/null", O_RDWR), STDOUT_FILENO) == -1)
101 die("Failed to dup2(STDOUT)");
102 break;
103 }
104 case Subprocess::kBuffer:
105 if (dup2(args->stdouterr_pipe_wr, STDOUT_FILENO) == -1)
106 die("Failed to dup2(STDOUT)");
107 break;
108 }
109
110 switch (args->create_args->stderr_mode) {
111 case Subprocess::kInherit:
112 break;
113 case Subprocess::kDevNull: {
114 if (dup2(open("/dev/null", O_RDWR), STDERR_FILENO) == -1)
115 die("Failed to dup2(STDERR)");
116 break;
117 }
118 case Subprocess::kBuffer:
119 if (dup2(args->stdouterr_pipe_wr, STDERR_FILENO) == -1)
120 die("Failed to dup2(STDERR)");
121 break;
122 }
123
124 // Close all FDs % stdin/out/err and the ones that the client explicitly
125 // asked to retain. The reason for this is twofold:
126 // 1. For exec-only (i.e. entrypoint == empty) cases: it avoids leaking FDs
127 // that didn't get marked as O_CLOEXEC by accident.
128 // 2. In fork() mode (entrypoint not empty) avoids retaining a dup of eventfds
129 // that would prevent the parent process to receive EOFs (tests usually use
130 // pipes as a synchronization mechanism between subprocesses).
131 const auto& preserve_fds = args->create_args->preserve_fds;
132 for (int i = 0; i < 512; i++) {
133 if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO &&
134 i != args->stdouterr_pipe_wr &&
135 !std::count(preserve_fds.begin(), preserve_fds.end(), i)) {
136 close(i);
137 }
138 }
139
140 // Clears O_CLOEXEC from stdin/out/err. These are the only FDs that we want
141 // to be preserved after the exec().
142 set_fd_close_on_exec(STDIN_FILENO, false);
143 set_fd_close_on_exec(STDOUT_FILENO, false);
144 set_fd_close_on_exec(STDERR_FILENO, false);
145
146 // If the caller specified a std::function entrypoint, run that first.
147 if (args->create_args->entrypoint_for_testing)
148 args->create_args->entrypoint_for_testing();
149
150 // If the caller specified only an entrypoint, without any args, exit now.
151 // Otherwise proceed with the exec() below.
152 if (!args->exec_cmd)
153 _exit(0);
154
155 // If |args[0]| is a path use execv() (which takes a path), othewise use
156 // exevp(), which uses the shell and follows PATH.
157 if (strchr(args->exec_cmd, '/')) {
158 char** env = args->env.empty() ? environ : args->env.data();
159 execve(args->exec_cmd, args->argv.data(), env);
160 } else {
161 // There is no execvpe() on Mac.
162 if (!args->env.empty())
163 die("A full path is required for |exec_cmd| when setting |env|");
164 execvp(args->exec_cmd, args->argv.data());
165 }
166
167 // Reached only if execv fails.
168 die("execve() failed");
169}
170
171} // namespace
172
Sami Kyostilaf059df72020-04-20 10:13:32 +0100173Subprocess::Args::Args(Args&&) noexcept = default;
174Subprocess::Args& Subprocess::Args::operator=(Args&&) = default;
175
Primiano Tuccie1a28482020-08-06 14:43:54 +0200176Subprocess::Subprocess(std::initializer_list<std::string> a) : args(a) {}
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000177
Primiano Tuccie1a28482020-08-06 14:43:54 +0200178Subprocess::Subprocess(Subprocess&& other) noexcept {
179 static_assert(sizeof(Subprocess) == sizeof(std::tuple<MovableState, Args>),
180 "base::Subprocess' move ctor needs updating");
181 s_ = std::move(other.s_);
182 args = std::move(other.args);
183
184 // Reset the state of the moved-from object.
185 other.s_.status = kNotStarted; // So the dtor doesn't try to kill().
186 other.~Subprocess();
187 new (&other) Subprocess();
188}
189
190Subprocess& Subprocess::operator=(Subprocess&& other) {
191 this->~Subprocess();
192 new (this) Subprocess(std::move(other));
193 return *this;
194}
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000195
196Subprocess::~Subprocess() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200197 if (s_.status == kRunning)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000198 KillAndWaitForTermination();
Primiano Tuccie1a28482020-08-06 14:43:54 +0200199 PERFETTO_CHECK(!s_.waitpid_thread.joinable());
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000200}
201
202void Subprocess::Start() {
203 ChildProcessArgs proc_args;
204 proc_args.create_args = &args;
205
206 // Setup argv.
207 if (!args.exec_cmd.empty()) {
208 proc_args.exec_cmd = args.exec_cmd[0].c_str();
209 for (const std::string& arg : args.exec_cmd)
210 proc_args.argv.push_back(const_cast<char*>(arg.c_str()));
211 proc_args.argv.push_back(nullptr);
212
213 if (!args.argv0_override.empty())
214 proc_args.argv[0] = const_cast<char*>(args.argv0_override.c_str());
215 }
216
217 // Setup env.
218 if (!args.env.empty()) {
219 for (const std::string& str : args.env)
220 proc_args.env.push_back(const_cast<char*>(str.c_str()));
221 proc_args.env.push_back(nullptr);
222 }
223
224 // Setup the pipes for stdin/err redirection.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200225 s_.stdin_pipe = base::Pipe::Create(base::Pipe::kWrNonBlock);
226 proc_args.stdin_pipe_rd = *s_.stdin_pipe.rd;
227 s_.stdouterr_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
228 proc_args.stdouterr_pipe_wr = *s_.stdouterr_pipe.wr;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000229
230 // Spawn the child process that will exec().
Primiano Tuccie1a28482020-08-06 14:43:54 +0200231 s_.pid = fork();
232 PERFETTO_CHECK(s_.pid >= 0);
233 if (s_.pid == 0) {
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000234 // Close the parent-ends of the pipes.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200235 s_.stdin_pipe.wr.reset();
236 s_.stdouterr_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000237 ChildProcess(&proc_args);
238 // ChildProcess() doesn't return, not even in case of failures.
239 PERFETTO_FATAL("not reached");
240 }
241
Primiano Tuccie1a28482020-08-06 14:43:54 +0200242 s_.status = kRunning;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000243
244 // Close the child-end of the pipes.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200245 // Deliberately NOT closing the s_.stdin_pipe.rd. This is to avoid crashing
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000246 // with a SIGPIPE if the process exits without consuming its stdin, while
247 // the parent tries to write() on the other end of the stdin pipe.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200248 s_.stdouterr_pipe.wr.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000249
250 // Spawn a thread that is blocked on waitpid() and writes the termination
251 // status onto a pipe. The problem here is that waipid() doesn't have a
252 // timeout option and can't be passed to poll(). The alternative would be
253 // using a SIGCHLD handler, but anecdotally signal handlers introduce more
254 // problems than what they solve.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200255 s_.exit_status_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000256
257 // Both ends of the pipe are closed after the thread.join().
Primiano Tuccie1a28482020-08-06 14:43:54 +0200258 int pid = s_.pid;
259 int exit_status_pipe_wr = s_.exit_status_pipe.wr.release();
260 s_.waitpid_thread = std::thread([pid, exit_status_pipe_wr] {
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000261 int pid_stat = -1;
262 int wait_res = PERFETTO_EINTR(waitpid(pid, &pid_stat, 0));
263 PERFETTO_CHECK(wait_res == pid);
264 base::ignore_result(PERFETTO_EINTR(
265 write(exit_status_pipe_wr, &pid_stat, sizeof(pid_stat))));
Ryan704bc822020-03-31 02:31:13 +0100266 PERFETTO_CHECK(close(exit_status_pipe_wr) == 0 || errno == EINTR);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000267 });
268}
269
270Subprocess::Status Subprocess::Poll() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200271 if (s_.status != kRunning)
272 return s_.status; // Nothing to poll.
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000273 while (PollInternal(0 /* don't block*/)) {
274 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200275 return s_.status;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000276}
277
278// |timeout_ms| semantic:
279// -1: Block indefinitely.
280// 0: Don't block, return immediately.
281// >0: Block for at most X ms.
282// Returns:
283// True: Read at least one fd (so there might be more queued).
284// False: if all fds reached quiescent (no data to read/write).
285bool Subprocess::PollInternal(int poll_timeout_ms) {
286 struct pollfd fds[3]{};
287 size_t num_fds = 0;
Primiano Tuccie1a28482020-08-06 14:43:54 +0200288 if (s_.exit_status_pipe.rd) {
289 fds[num_fds].fd = *s_.exit_status_pipe.rd;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000290 fds[num_fds].events = POLLIN;
291 num_fds++;
292 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200293 if (s_.stdouterr_pipe.rd) {
294 fds[num_fds].fd = *s_.stdouterr_pipe.rd;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000295 fds[num_fds].events = POLLIN;
296 num_fds++;
297 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200298 if (s_.stdin_pipe.wr) {
299 fds[num_fds].fd = *s_.stdin_pipe.wr;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000300 fds[num_fds].events = POLLOUT;
301 num_fds++;
302 }
303
304 if (num_fds == 0)
305 return false;
306
307 auto nfds = static_cast<nfds_t>(num_fds);
308 int poll_res = PERFETTO_EINTR(poll(fds, nfds, poll_timeout_ms));
309 PERFETTO_CHECK(poll_res >= 0);
310
311 TryReadStdoutAndErr();
312 TryPushStdin();
313 TryReadExitStatus();
314
315 return poll_res > 0;
316}
317
318bool Subprocess::Wait(int timeout_ms) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200319 PERFETTO_CHECK(s_.status != kNotStarted);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000320
321 // Break out of the loop only after both conditions are satisfied:
322 // - All stdout/stderr data has been read (if kBuffer).
323 // - The process exited.
324 // Note that the two events can happen arbitrary order. After the process
325 // exits, there might be still data in the pipe buffer, which we want to
326 // read fully.
327 //
328 // Instead, don't wait on the stdin to be fully written. The child process
329 // might exit prematurely (or crash). If that happens, we can end up in a
330 // state where the write(stdin_pipe_.wr) will never unblock.
331
332 const int64_t t_start = base::GetWallTimeMs().count();
Primiano Tuccie1a28482020-08-06 14:43:54 +0200333 while (s_.exit_status_pipe.rd || s_.stdouterr_pipe.rd) {
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000334 int poll_timeout_ms = -1; // Block until a FD is ready.
335 if (timeout_ms > 0) {
336 const int64_t now = GetWallTimeMs().count();
337 poll_timeout_ms = timeout_ms - static_cast<int>(now - t_start);
338 if (poll_timeout_ms <= 0)
339 return false;
340 }
341 PollInternal(poll_timeout_ms);
342 } // while(...)
343 return true;
344}
345
346bool Subprocess::Call(int timeout_ms) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200347 PERFETTO_CHECK(s_.status == kNotStarted);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000348 Start();
349
350 if (!Wait(timeout_ms)) {
351 KillAndWaitForTermination();
352 // TryReadExitStatus must have joined the thread.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200353 PERFETTO_DCHECK(!s_.waitpid_thread.joinable());
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000354 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200355 PERFETTO_DCHECK(s_.status != kRunning);
356 return s_.status == kExited && s_.returncode == 0;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000357}
358
359void Subprocess::TryReadExitStatus() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200360 if (!s_.exit_status_pipe.rd)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000361 return;
362
363 int pid_stat = -1;
Primiano Tuccie1a28482020-08-06 14:43:54 +0200364 int64_t rsize = PERFETTO_EINTR(
365 read(*s_.exit_status_pipe.rd, &pid_stat, sizeof(pid_stat)));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000366 if (rsize < 0 && errno == EAGAIN)
367 return;
368
369 if (rsize > 0) {
370 PERFETTO_CHECK(rsize == sizeof(pid_stat));
371 } else if (rsize < 0) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200372 PERFETTO_PLOG("Subprocess read(s_.exit_status_pipe) failed");
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000373 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200374 s_.waitpid_thread.join();
375 s_.exit_status_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000376
377 if (WIFEXITED(pid_stat)) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200378 s_.returncode = WEXITSTATUS(pid_stat);
379 s_.status = kExited;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000380 } else if (WIFSIGNALED(pid_stat)) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200381 s_.returncode = 128 + WTERMSIG(pid_stat); // Follow bash convention.
382 s_.status = kKilledBySignal;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000383 } else {
384 PERFETTO_FATAL("waitpid() returned an unexpected value (0x%x)", pid_stat);
385 }
386}
387
388// If the stidn pipe is still open, push input data and close it at the end.
389void Subprocess::TryPushStdin() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200390 if (!s_.stdin_pipe.wr)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000391 return;
392
Primiano Tuccie1a28482020-08-06 14:43:54 +0200393 PERFETTO_DCHECK(args.input.empty() || s_.input_written < args.input.size());
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000394 if (args.input.size()) {
395 int64_t wsize =
Primiano Tuccie1a28482020-08-06 14:43:54 +0200396 PERFETTO_EINTR(write(*s_.stdin_pipe.wr, &args.input[s_.input_written],
397 args.input.size() - s_.input_written));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000398 if (wsize < 0 && errno == EAGAIN)
399 return;
400
401 if (wsize >= 0) {
402 // Whether write() can return 0 is one of the greatest mysteries of UNIX.
403 // Just ignore it.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200404 s_.input_written += static_cast<size_t>(wsize);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000405 } else {
406 PERFETTO_PLOG("Subprocess write(stdin) failed");
Primiano Tuccie1a28482020-08-06 14:43:54 +0200407 s_.stdin_pipe.wr.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000408 }
409 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200410 PERFETTO_DCHECK(s_.input_written <= args.input.size());
411 if (s_.input_written == args.input.size())
412 s_.stdin_pipe.wr.reset(); // Close stdin.
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000413}
414
415void Subprocess::TryReadStdoutAndErr() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200416 if (!s_.stdouterr_pipe.rd)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000417 return;
418 char buf[4096];
Primiano Tuccie1a28482020-08-06 14:43:54 +0200419 int64_t rsize = PERFETTO_EINTR(read(*s_.stdouterr_pipe.rd, buf, sizeof(buf)));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000420 if (rsize < 0 && errno == EAGAIN)
421 return;
422
423 if (rsize > 0) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200424 s_.output.append(buf, static_cast<size_t>(rsize));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000425 } else if (rsize == 0 /* EOF */) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200426 s_.stdouterr_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000427 } else {
428 PERFETTO_PLOG("Subprocess read(stdout/err) failed");
Primiano Tuccie1a28482020-08-06 14:43:54 +0200429 s_.stdouterr_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000430 }
431}
432
433void Subprocess::KillAndWaitForTermination() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200434 kill(s_.pid, SIGKILL);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000435 Wait();
436}
437
438std::string Subprocess::Args::GetCmdString() const {
439 std::string str;
440 for (size_t i = 0; i < exec_cmd.size(); i++) {
441 str += i > 0 ? " \"" : "";
442 str += exec_cmd[i];
443 str += i > 0 ? "\"" : "";
444 }
445 return str;
446}
447
448} // namespace base
449} // namespace perfetto
Primiano Tucci1797cd12020-04-14 09:43:24 +0100450
451#endif // PERFETTO_HAS_SUBPROCESS()