1 /*
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 
19 #include "perfetto/base/build_config.h"
20 
21 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
22 
23 #include <stdio.h>
24 
25 #include <algorithm>
26 #include <mutex>
27 #include <tuple>
28 
29 #include <Windows.h>
30 
31 #include "perfetto/base/logging.h"
32 #include "perfetto/base/time.h"
33 #include "perfetto/ext/base/pipe.h"
34 #include "perfetto/ext/base/utils.h"
35 
36 namespace perfetto {
37 namespace base {
38 
39 // static
40 const int Subprocess::kTimeoutSignal = static_cast<int>(STATUS_TIMEOUT);
41 
Start()42 void Subprocess::Start() {
43   if (args.exec_cmd.empty()) {
44     PERFETTO_ELOG("Subprocess.exec_cmd cannot be empty on Windows");
45     return;
46   }
47 
48   // Quote arguments but only when ambiguous. When quoting, CreateProcess()
49   // assumes that the command is an absolute path and does not search in the
50   // %PATH%. If non quoted, instead, CreateProcess() tries both. This is to
51   // allow Subprocess("cmd.exe", "/c", "shell command").
52   std::string cmd;
53   for (const auto& part : args.exec_cmd) {
54     if (part.find(" ") != std::string::npos) {
55       cmd += "\"" + part + "\" ";
56     } else {
57       cmd += part + " ";
58     }
59   }
60   // Remove trailing space.
61   if (!cmd.empty())
62     cmd.resize(cmd.size() - 1);
63 
64   s_->stdin_pipe = Pipe::Create();
65   // Allow the child process to inherit the other end of the pipe.
66   PERFETTO_CHECK(
67       ::SetHandleInformation(*s_->stdin_pipe.rd, HANDLE_FLAG_INHERIT, 1));
68 
69   if (args.stderr_mode == kBuffer || args.stdout_mode == kBuffer) {
70     s_->stdouterr_pipe = Pipe::Create();
71     PERFETTO_CHECK(
72         ::SetHandleInformation(*s_->stdouterr_pipe.wr, HANDLE_FLAG_INHERIT, 1));
73   }
74 
75   ScopedPlatformHandle nul_handle;
76   if (args.stderr_mode == kDevNull || args.stdout_mode == kDevNull) {
77     nul_handle.reset(::CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
78                                    nullptr, OPEN_EXISTING,
79                                    FILE_ATTRIBUTE_NORMAL, nullptr));
80     PERFETTO_CHECK(::SetHandleInformation(*nul_handle, HANDLE_FLAG_INHERIT, 1));
81   }
82 
83   PROCESS_INFORMATION proc_info{};
84   STARTUPINFOA start_info{};
85   start_info.cb = sizeof(STARTUPINFOA);
86 
87   if (args.stderr_mode == kInherit) {
88     start_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
89   } else if (args.stderr_mode == kBuffer) {
90     start_info.hStdError = *s_->stdouterr_pipe.wr;
91   } else if (args.stderr_mode == kDevNull) {
92     start_info.hStdError = *nul_handle;
93   } else if (args.stderr_mode == kFd) {
94     PERFETTO_CHECK(
95         ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
96     start_info.hStdError = *args.out_fd;
97   } else {
98     PERFETTO_CHECK(false);
99   }
100 
101   if (args.stdout_mode == kInherit) {
102     start_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
103   } else if (args.stdout_mode == kBuffer) {
104     start_info.hStdOutput = *s_->stdouterr_pipe.wr;
105   } else if (args.stdout_mode == kDevNull) {
106     start_info.hStdOutput = *nul_handle;
107   } else if (args.stdout_mode == kFd) {
108     PERFETTO_CHECK(
109         ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
110     start_info.hStdOutput = *args.out_fd;
111   } else {
112     PERFETTO_CHECK(false);
113   }
114 
115   start_info.hStdInput = *s_->stdin_pipe.rd;
116   start_info.dwFlags |= STARTF_USESTDHANDLES;
117 
118   // Create the child process.
119   bool success =
120       ::CreateProcessA(nullptr,      // App name. Needs to be null to use PATH.
121                        &cmd[0],      // Command line.
122                        nullptr,      // Process security attributes.
123                        nullptr,      // Primary thread security attributes.
124                        true,         // Handles are inherited.
125                        0,            // Flags.
126                        nullptr,      // Use parent's environment.
127                        nullptr,      // Use parent's current directory.
128                        &start_info,  // STARTUPINFO pointer.
129                        &proc_info);  // Receives PROCESS_INFORMATION.
130 
131   // Close on our side the pipe ends that we passed to the child process.
132   s_->stdin_pipe.rd.reset();
133   s_->stdouterr_pipe.wr.reset();
134   args.out_fd.reset();
135 
136   if (!success) {
137     s_->returncode = ERROR_FILE_NOT_FOUND;
138     s_->status = kTerminated;
139     s_->stdin_pipe.wr.reset();
140     s_->stdouterr_pipe.rd.reset();
141     PERFETTO_ELOG("CreateProcess failed: %lx, cmd: %s", GetLastError(),
142                   &cmd[0]);
143     return;
144   }
145 
146   s_->pid = proc_info.dwProcessId;
147   s_->win_proc_handle = ScopedPlatformHandle(proc_info.hProcess);
148   s_->win_thread_handle = ScopedPlatformHandle(proc_info.hThread);
149   s_->status = kRunning;
150 
151   MovableState* s = s_.get();
152   s_->stdin_thread = std::thread(&Subprocess::StdinThread, s, args.input);
153 
154   if (args.stderr_mode == kBuffer || args.stdout_mode == kBuffer) {
155     PERFETTO_DCHECK(s_->stdouterr_pipe.rd);
156     s_->stdouterr_thread = std::thread(&Subprocess::StdoutErrThread, s);
157   }
158 }
159 
160 // static
StdinThread(MovableState * s,std::string input)161 void Subprocess::StdinThread(MovableState* s, std::string input) {
162   size_t input_written = 0;
163   while (input_written < input.size()) {
164     DWORD wsize = 0;
165     if (::WriteFile(*s->stdin_pipe.wr, input.data() + input_written,
166                     static_cast<DWORD>(input.size() - input_written), &wsize,
167                     nullptr)) {
168       input_written += wsize;
169     } else {
170       // ERROR_BROKEN_PIPE is WAI when the child just closes stdin and stops
171       // accepting input.
172       auto err = ::GetLastError();
173       if (err != ERROR_BROKEN_PIPE)
174         PERFETTO_PLOG("Subprocess WriteFile(stdin) failed %lx", err);
175       break;
176     }
177   }  // while(...)
178   std::unique_lock<std::mutex> lock(s->mutex);
179   s->stdin_pipe.wr.reset();
180 }
181 
182 // static
StdoutErrThread(MovableState * s)183 void Subprocess::StdoutErrThread(MovableState* s) {
184   char buf[4096];
185   for (;;) {
186     DWORD rsize = 0;
187     bool res =
188         ::ReadFile(*s->stdouterr_pipe.rd, buf, sizeof(buf), &rsize, nullptr);
189     if (!res) {
190       auto err = GetLastError();
191       if (err != ERROR_BROKEN_PIPE)
192         PERFETTO_PLOG("Subprocess ReadFile(stdouterr) failed %ld", err);
193     }
194 
195     if (rsize > 0) {
196       std::unique_lock<std::mutex> lock(s->mutex);
197       s->locked_outerr_buf.append(buf, static_cast<size_t>(rsize));
198     } else {  // EOF or some error.
199       break;
200     }
201   }  // For(..)
202 
203   // Close the stdouterr_pipe. The main loop looks at the pipe closure to
204   // determine whether the stdout/err thread has completed.
205   {
206     std::unique_lock<std::mutex> lock(s->mutex);
207     s->stdouterr_pipe.rd.reset();
208   }
209   s->stdouterr_done_event.Notify();
210 }
211 
Poll()212 Subprocess::Status Subprocess::Poll() {
213   if (s_->status != kRunning)
214     return s_->status;  // Nothing to poll.
215   Wait(1 /*ms*/);
216   return s_->status;
217 }
218 
Wait(int timeout_ms)219 bool Subprocess::Wait(int timeout_ms) {
220   PERFETTO_CHECK(s_->status != kNotStarted);
221   const bool wait_forever = timeout_ms == 0;
222   const int64_t wait_start_ms = base::GetWallTimeMs().count();
223 
224   // Break out of the loop only after both conditions are satisfied:
225   // - All stdout/stderr data has been read (if kBuffer).
226   // - The process exited.
227   // Note that the two events can happen arbitrary order. After the process
228   // exits, there might be still data in the pipe buffer, which we want to
229   // read fully.
230   // Note also that stdout/err might be "complete" before starting, if neither
231   // is operating in kBuffer mode. In that case we just want to wait for the
232   // process termination.
233   //
234   // Instead, don't wait on the stdin to be fully written. The child process
235   // might exit prematurely (or crash). If that happens, we can end up in a
236   // state where the write(stdin_pipe_.wr) will never unblock.
237   bool stdouterr_complete = false;
238   for (;;) {
239     HANDLE wait_handles[2]{};
240     DWORD num_handles = 0;
241 
242     // Check if the process exited.
243     bool process_exited = !s_->win_proc_handle;
244     if (!process_exited) {
245       DWORD exit_code = STILL_ACTIVE;
246       PERFETTO_CHECK(::GetExitCodeProcess(*s_->win_proc_handle, &exit_code));
247       if (exit_code != STILL_ACTIVE) {
248         s_->returncode = static_cast<int>(exit_code);
249         s_->status = kTerminated;
250         s_->win_proc_handle.reset();
251         s_->win_thread_handle.reset();
252         process_exited = true;
253       }
254     } else {
255       PERFETTO_DCHECK(s_->status != kRunning);
256     }
257     if (!process_exited) {
258       wait_handles[num_handles++] = *s_->win_proc_handle;
259     }
260 
261     // Check if there is more output and if the stdout/err pipe has been closed.
262     {
263       std::unique_lock<std::mutex> lock(s_->mutex);
264       // Move the output from the internal buffer shared with the
265       // stdouterr_thread to the final buffer exposed to the client.
266       if (!s_->locked_outerr_buf.empty()) {
267         s_->output.append(std::move(s_->locked_outerr_buf));
268         s_->locked_outerr_buf.clear();
269       }
270       stdouterr_complete = !s_->stdouterr_pipe.rd;
271       if (!stdouterr_complete) {
272         wait_handles[num_handles++] = s_->stdouterr_done_event.fd();
273       }
274     }  // lock(s_->mutex)
275 
276     if (num_handles == 0) {
277       PERFETTO_DCHECK(process_exited && stdouterr_complete);
278       break;
279     }
280 
281     DWORD wait_ms;  // Note: DWORD is unsigned.
282     if (wait_forever) {
283       wait_ms = INFINITE;
284     } else {
285       const int64_t now = GetWallTimeMs().count();
286       const int64_t wait_left_ms = timeout_ms - (now - wait_start_ms);
287       if (wait_left_ms <= 0)
288         return false;  // Timed out
289       wait_ms = static_cast<DWORD>(wait_left_ms);
290     }
291 
292     auto wait_res =
293         ::WaitForMultipleObjects(num_handles, wait_handles, false, wait_ms);
294     PERFETTO_CHECK(wait_res != WAIT_FAILED);
295   }
296 
297   PERFETTO_DCHECK(!s_->win_proc_handle);
298   PERFETTO_DCHECK(!s_->win_thread_handle);
299 
300   if (s_->stdin_thread.joinable())  // Might not exist if CreateProcess failed.
301     s_->stdin_thread.join();
302   if (s_->stdouterr_thread.joinable())
303     s_->stdouterr_thread.join();
304 
305   // The stdin pipe is closed by the dedicated stdin thread. However if that is
306   // not started (e.g. because of no redirection) force close it now. Needs to
307   // happen after the join() to be thread safe.
308   s_->stdin_pipe.wr.reset();
309   s_->stdouterr_pipe.rd.reset();
310 
311   return true;
312 }
313 
KillAndWaitForTermination(int exit_code)314 void Subprocess::KillAndWaitForTermination(int exit_code) {
315   auto code = exit_code ? static_cast<DWORD>(exit_code) : STATUS_CONTROL_C_EXIT;
316   ::TerminateProcess(*s_->win_proc_handle, code);
317   Wait();
318   // TryReadExitStatus must have joined the threads.
319   PERFETTO_DCHECK(!s_->stdin_thread.joinable());
320   PERFETTO_DCHECK(!s_->stdouterr_thread.joinable());
321 }
322 
323 }  // namespace base
324 }  // namespace perfetto
325 
326 #endif  // PERFETTO_OS_WIN
327