OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/process/launch.h" | 5 #include "base/process/launch.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <io.h> | 8 #include <io.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 #include <windows.h> | 10 #include <windows.h> |
(...skipping 28 matching lines...) Expand all Loading... |
39 namespace { | 39 namespace { |
40 | 40 |
41 // This exit code is used by the Windows task manager when it kills a | 41 // This exit code is used by the Windows task manager when it kills a |
42 // process. It's value is obviously not that unique, and it's | 42 // process. It's value is obviously not that unique, and it's |
43 // surprising to me that the task manager uses this value, but it | 43 // surprising to me that the task manager uses this value, but it |
44 // seems to be common practice on Windows to test for it as an | 44 // seems to be common practice on Windows to test for it as an |
45 // indication that the task manager has killed something if the | 45 // indication that the task manager has killed something if the |
46 // process goes away. | 46 // process goes away. |
47 const DWORD kProcessKilledExitCode = 1; | 47 const DWORD kProcessKilledExitCode = 1; |
48 | 48 |
| 49 bool GetAppOutputInternal(const StringPiece16& cl, |
| 50 bool include_stderr, |
| 51 std::string* output) { |
| 52 HANDLE out_read = NULL; |
| 53 HANDLE out_write = NULL; |
| 54 |
| 55 SECURITY_ATTRIBUTES sa_attr; |
| 56 // Set the bInheritHandle flag so pipe handles are inherited. |
| 57 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); |
| 58 sa_attr.bInheritHandle = TRUE; |
| 59 sa_attr.lpSecurityDescriptor = NULL; |
| 60 |
| 61 // Create the pipe for the child process's STDOUT. |
| 62 if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { |
| 63 NOTREACHED() << "Failed to create pipe"; |
| 64 return false; |
| 65 } |
| 66 |
| 67 // Ensure we don't leak the handles. |
| 68 win::ScopedHandle scoped_out_read(out_read); |
| 69 win::ScopedHandle scoped_out_write(out_write); |
| 70 |
| 71 // Ensure the read handles to the pipes are not inherited. |
| 72 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { |
| 73 NOTREACHED() << "Failed to disabled pipe inheritance"; |
| 74 return false; |
| 75 } |
| 76 |
| 77 FilePath::StringType writable_command_line_string; |
| 78 writable_command_line_string.assign(cl.data(), cl.size()); |
| 79 |
| 80 STARTUPINFO start_info = {}; |
| 81 |
| 82 start_info.cb = sizeof(STARTUPINFO); |
| 83 start_info.hStdOutput = out_write; |
| 84 // Keep the normal stdin. |
| 85 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
| 86 if (include_stderr) { |
| 87 start_info.hStdError = out_write; |
| 88 } else { |
| 89 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
| 90 } |
| 91 start_info.dwFlags |= STARTF_USESTDHANDLES; |
| 92 |
| 93 // Create the child process. |
| 94 PROCESS_INFORMATION temp_process_info = {}; |
| 95 if (!CreateProcess(NULL, |
| 96 &writable_command_line_string[0], |
| 97 NULL, NULL, |
| 98 TRUE, // Handles are inherited. |
| 99 0, NULL, NULL, &start_info, &temp_process_info)) { |
| 100 NOTREACHED() << "Failed to start process"; |
| 101 return false; |
| 102 } |
| 103 base::win::ScopedProcessInformation proc_info(temp_process_info); |
| 104 |
| 105 // Close our writing end of pipe now. Otherwise later read would not be able |
| 106 // to detect end of child's output. |
| 107 scoped_out_write.Close(); |
| 108 |
| 109 // Read output from the child process's pipe for STDOUT |
| 110 const int kBufferSize = 1024; |
| 111 char buffer[kBufferSize]; |
| 112 |
| 113 for (;;) { |
| 114 DWORD bytes_read = 0; |
| 115 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); |
| 116 if (!success || bytes_read == 0) |
| 117 break; |
| 118 output->append(buffer, bytes_read); |
| 119 } |
| 120 |
| 121 // Let's wait for the process to finish. |
| 122 WaitForSingleObject(proc_info.process_handle(), INFINITE); |
| 123 |
| 124 int exit_code; |
| 125 base::TerminationStatus status = GetTerminationStatus( |
| 126 proc_info.process_handle(), &exit_code); |
| 127 return status != base::TERMINATION_STATUS_PROCESS_CRASHED && |
| 128 status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION; |
| 129 } |
| 130 |
49 } // namespace | 131 } // namespace |
50 | 132 |
51 void RouteStdioToConsole() { | 133 void RouteStdioToConsole(bool create_console_if_not_found) { |
52 // Don't change anything if stdout or stderr already point to a | 134 // Don't change anything if stdout or stderr already point to a |
53 // valid stream. | 135 // valid stream. |
54 // | 136 // |
55 // If we are running under Buildbot or under Cygwin's default | 137 // If we are running under Buildbot or under Cygwin's default |
56 // terminal (mintty), stderr and stderr will be pipe handles. In | 138 // terminal (mintty), stderr and stderr will be pipe handles. In |
57 // that case, we don't want to open CONOUT$, because its output | 139 // that case, we don't want to open CONOUT$, because its output |
58 // likely does not go anywhere. | 140 // likely does not go anywhere. |
59 // | 141 // |
60 // We don't use GetStdHandle() to check stdout/stderr here because | 142 // We don't use GetStdHandle() to check stdout/stderr here because |
61 // it can return dangling IDs of handles that were never inherited | 143 // it can return dangling IDs of handles that were never inherited |
62 // by this process. These IDs could have been reused by the time | 144 // by this process. These IDs could have been reused by the time |
63 // this function is called. The CRT checks the validity of | 145 // this function is called. The CRT checks the validity of |
64 // stdout/stderr on startup (before the handle IDs can be reused). | 146 // stdout/stderr on startup (before the handle IDs can be reused). |
65 // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was | 147 // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was |
66 // invalid. | 148 // invalid. |
67 if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) | 149 if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) { |
68 return; | 150 // _fileno was broken for SUBSYSTEM:WINDOWS from VS2010 to VS2012/2013. |
| 151 // http://crbug.com/358267. Confirm that the underlying HANDLE is valid |
| 152 // before aborting. |
| 153 |
| 154 // This causes NaCl tests to hang on XP for reasons unclear, perhaps due |
| 155 // to not being able to inherit handles. Since it's only for debugging, |
| 156 // and redirecting still works, punt for now. |
| 157 if (base::win::GetVersion() < base::win::VERSION_VISTA) |
| 158 return; |
| 159 |
| 160 intptr_t stdout_handle = _get_osfhandle(_fileno(stdout)); |
| 161 intptr_t stderr_handle = _get_osfhandle(_fileno(stderr)); |
| 162 if (stdout_handle >= 0 || stderr_handle >= 0) |
| 163 return; |
| 164 } |
69 | 165 |
70 if (!AttachConsole(ATTACH_PARENT_PROCESS)) { | 166 if (!AttachConsole(ATTACH_PARENT_PROCESS)) { |
71 unsigned int result = GetLastError(); | 167 unsigned int result = GetLastError(); |
72 // Was probably already attached. | 168 // Was probably already attached. |
73 if (result == ERROR_ACCESS_DENIED) | 169 if (result == ERROR_ACCESS_DENIED) |
74 return; | 170 return; |
75 // Don't bother creating a new console for each child process if the | 171 // Don't bother creating a new console for each child process if the |
76 // parent process is invalid (eg: crashed). | 172 // parent process is invalid (eg: crashed). |
77 if (result == ERROR_GEN_FAILURE) | 173 if (result == ERROR_GEN_FAILURE) |
78 return; | 174 return; |
79 // Make a new console if attaching to parent fails with any other error. | 175 if (create_console_if_not_found) { |
80 // It should be ERROR_INVALID_HANDLE at this point, which means the browser | 176 // Make a new console if attaching to parent fails with any other error. |
81 // was likely not started from a console. | 177 // It should be ERROR_INVALID_HANDLE at this point, which means the |
82 AllocConsole(); | 178 // browser was likely not started from a console. |
| 179 AllocConsole(); |
| 180 } |
83 } | 181 } |
84 | 182 |
85 // Arbitrary byte count to use when buffering output lines. More | 183 // Arbitrary byte count to use when buffering output lines. More |
86 // means potential waste, less means more risk of interleaved | 184 // means potential waste, less means more risk of interleaved |
87 // log-lines in output. | 185 // log-lines in output. |
88 enum { kOutputBufferSize = 64 * 1024 }; | 186 enum { kOutputBufferSize = 64 * 1024 }; |
89 | 187 |
90 if (freopen("CONOUT$", "w", stdout)) { | 188 if (freopen("CONOUT$", "w", stdout)) { |
91 setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize); | 189 setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize); |
92 // Overwrite FD 1 for the benefit of any code that uses this FD | 190 // Overwrite FD 1 for the benefit of any code that uses this FD |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 job_object, | 365 job_object, |
268 JobObjectExtendedLimitInformation, | 366 JobObjectExtendedLimitInformation, |
269 &limit_info, | 367 &limit_info, |
270 sizeof(limit_info)); | 368 sizeof(limit_info)); |
271 } | 369 } |
272 | 370 |
273 bool GetAppOutput(const CommandLine& cl, std::string* output) { | 371 bool GetAppOutput(const CommandLine& cl, std::string* output) { |
274 return GetAppOutput(cl.GetCommandLineString(), output); | 372 return GetAppOutput(cl.GetCommandLineString(), output); |
275 } | 373 } |
276 | 374 |
| 375 bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { |
| 376 return GetAppOutputInternal(cl.GetCommandLineString(), true, output); |
| 377 } |
| 378 |
277 bool GetAppOutput(const StringPiece16& cl, std::string* output) { | 379 bool GetAppOutput(const StringPiece16& cl, std::string* output) { |
278 HANDLE out_read = NULL; | 380 return GetAppOutputInternal(cl, false, output); |
279 HANDLE out_write = NULL; | |
280 | |
281 SECURITY_ATTRIBUTES sa_attr; | |
282 // Set the bInheritHandle flag so pipe handles are inherited. | |
283 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
284 sa_attr.bInheritHandle = TRUE; | |
285 sa_attr.lpSecurityDescriptor = NULL; | |
286 | |
287 // Create the pipe for the child process's STDOUT. | |
288 if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { | |
289 NOTREACHED() << "Failed to create pipe"; | |
290 return false; | |
291 } | |
292 | |
293 // Ensure we don't leak the handles. | |
294 win::ScopedHandle scoped_out_read(out_read); | |
295 win::ScopedHandle scoped_out_write(out_write); | |
296 | |
297 // Ensure the read handle to the pipe for STDOUT is not inherited. | |
298 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { | |
299 NOTREACHED() << "Failed to disabled pipe inheritance"; | |
300 return false; | |
301 } | |
302 | |
303 FilePath::StringType writable_command_line_string; | |
304 writable_command_line_string.assign(cl.data(), cl.size()); | |
305 | |
306 STARTUPINFO start_info = {}; | |
307 | |
308 start_info.cb = sizeof(STARTUPINFO); | |
309 start_info.hStdOutput = out_write; | |
310 // Keep the normal stdin and stderr. | |
311 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | |
312 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | |
313 start_info.dwFlags |= STARTF_USESTDHANDLES; | |
314 | |
315 // Create the child process. | |
316 PROCESS_INFORMATION temp_process_info = {}; | |
317 if (!CreateProcess(NULL, | |
318 &writable_command_line_string[0], | |
319 NULL, NULL, | |
320 TRUE, // Handles are inherited. | |
321 0, NULL, NULL, &start_info, &temp_process_info)) { | |
322 NOTREACHED() << "Failed to start process"; | |
323 return false; | |
324 } | |
325 base::win::ScopedProcessInformation proc_info(temp_process_info); | |
326 | |
327 // Close our writing end of pipe now. Otherwise later read would not be able | |
328 // to detect end of child's output. | |
329 scoped_out_write.Close(); | |
330 | |
331 // Read output from the child process's pipe for STDOUT | |
332 const int kBufferSize = 1024; | |
333 char buffer[kBufferSize]; | |
334 | |
335 for (;;) { | |
336 DWORD bytes_read = 0; | |
337 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); | |
338 if (!success || bytes_read == 0) | |
339 break; | |
340 output->append(buffer, bytes_read); | |
341 } | |
342 | |
343 // Let's wait for the process to finish. | |
344 WaitForSingleObject(proc_info.process_handle(), INFINITE); | |
345 | |
346 return true; | |
347 } | 381 } |
348 | 382 |
349 void RaiseProcessToHighPriority() { | 383 void RaiseProcessToHighPriority() { |
350 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); | 384 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
351 } | 385 } |
352 | 386 |
353 } // namespace base | 387 } // namespace base |
OLD | NEW |