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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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, | 49 bool GetAppOutputInternal(const StringPiece16& cl, |
50 bool include_stderr, | 50 bool include_stderr, |
51 std::string* output) { | 51 std::string* output) { |
52 HANDLE out_read = NULL; | 52 HANDLE out_read = nullptr; |
53 HANDLE out_write = NULL; | 53 HANDLE out_write = nullptr; |
54 | 54 |
55 SECURITY_ATTRIBUTES sa_attr; | 55 SECURITY_ATTRIBUTES sa_attr; |
56 // Set the bInheritHandle flag so pipe handles are inherited. | 56 // Set the bInheritHandle flag so pipe handles are inherited. |
57 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); | 57 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); |
58 sa_attr.bInheritHandle = TRUE; | 58 sa_attr.bInheritHandle = TRUE; |
59 sa_attr.lpSecurityDescriptor = NULL; | 59 sa_attr.lpSecurityDescriptor = nullptr; |
60 | 60 |
61 // Create the pipe for the child process's STDOUT. | 61 // Create the pipe for the child process's STDOUT. |
62 if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { | 62 if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { |
63 NOTREACHED() << "Failed to create pipe"; | 63 NOTREACHED() << "Failed to create pipe"; |
64 return false; | 64 return false; |
65 } | 65 } |
66 | 66 |
67 // Ensure we don't leak the handles. | 67 // Ensure we don't leak the handles. |
68 win::ScopedHandle scoped_out_read(out_read); | 68 win::ScopedHandle scoped_out_read(out_read); |
69 win::ScopedHandle scoped_out_write(out_write); | 69 win::ScopedHandle scoped_out_write(out_write); |
(...skipping 15 matching lines...) Expand all Loading... |
85 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | 85 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
86 if (include_stderr) { | 86 if (include_stderr) { |
87 start_info.hStdError = out_write; | 87 start_info.hStdError = out_write; |
88 } else { | 88 } else { |
89 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | 89 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
90 } | 90 } |
91 start_info.dwFlags |= STARTF_USESTDHANDLES; | 91 start_info.dwFlags |= STARTF_USESTDHANDLES; |
92 | 92 |
93 // Create the child process. | 93 // Create the child process. |
94 PROCESS_INFORMATION temp_process_info = {}; | 94 PROCESS_INFORMATION temp_process_info = {}; |
95 if (!CreateProcess(NULL, | 95 if (!CreateProcess(nullptr, &writable_command_line_string[0], nullptr, |
96 &writable_command_line_string[0], | 96 nullptr, |
97 NULL, NULL, | |
98 TRUE, // Handles are inherited. | 97 TRUE, // Handles are inherited. |
99 0, NULL, NULL, &start_info, &temp_process_info)) { | 98 0, nullptr, nullptr, &start_info, &temp_process_info)) { |
100 NOTREACHED() << "Failed to start process"; | 99 NOTREACHED() << "Failed to start process"; |
101 return false; | 100 return false; |
102 } | 101 } |
103 base::win::ScopedProcessInformation proc_info(temp_process_info); | 102 base::win::ScopedProcessInformation proc_info(temp_process_info); |
104 | 103 |
105 // Close our writing end of pipe now. Otherwise later read would not be able | 104 // Close our writing end of pipe now. Otherwise later read would not be able |
106 // to detect end of child's output. | 105 // to detect end of child's output. |
107 scoped_out_write.Close(); | 106 scoped_out_write.Close(); |
108 | 107 |
109 // Read output from the child process's pipe for STDOUT | 108 // Read output from the child process's pipe for STDOUT |
110 const int kBufferSize = 1024; | 109 const int kBufferSize = 1024; |
111 char buffer[kBufferSize]; | 110 char buffer[kBufferSize]; |
112 | 111 |
113 for (;;) { | 112 for (;;) { |
114 DWORD bytes_read = 0; | 113 DWORD bytes_read = 0; |
115 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); | 114 BOOL success = |
| 115 ReadFile(out_read, buffer, kBufferSize, &bytes_read, nullptr); |
116 if (!success || bytes_read == 0) | 116 if (!success || bytes_read == 0) |
117 break; | 117 break; |
118 output->append(buffer, bytes_read); | 118 output->append(buffer, bytes_read); |
119 } | 119 } |
120 | 120 |
121 // Let's wait for the process to finish. | 121 // Let's wait for the process to finish. |
122 WaitForSingleObject(proc_info.process_handle(), INFINITE); | 122 WaitForSingleObject(proc_info.process_handle(), INFINITE); |
123 | 123 |
124 int exit_code; | 124 int exit_code; |
125 base::TerminationStatus status = GetTerminationStatus( | 125 base::TerminationStatus status = GetTerminationStatus( |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 return; | 181 return; |
182 } | 182 } |
183 } | 183 } |
184 | 184 |
185 // Arbitrary byte count to use when buffering output lines. More | 185 // Arbitrary byte count to use when buffering output lines. More |
186 // means potential waste, less means more risk of interleaved | 186 // means potential waste, less means more risk of interleaved |
187 // log-lines in output. | 187 // log-lines in output. |
188 enum { kOutputBufferSize = 64 * 1024 }; | 188 enum { kOutputBufferSize = 64 * 1024 }; |
189 | 189 |
190 if (freopen("CONOUT$", "w", stdout)) { | 190 if (freopen("CONOUT$", "w", stdout)) { |
191 setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize); | 191 setvbuf(stdout, nullptr, _IOLBF, kOutputBufferSize); |
192 // Overwrite FD 1 for the benefit of any code that uses this FD | 192 // Overwrite FD 1 for the benefit of any code that uses this FD |
193 // directly. This is safe because the CRT allocates FDs 0, 1 and | 193 // directly. This is safe because the CRT allocates FDs 0, 1 and |
194 // 2 at startup even if they don't have valid underlying Windows | 194 // 2 at startup even if they don't have valid underlying Windows |
195 // handles. This means we won't be overwriting an FD created by | 195 // handles. This means we won't be overwriting an FD created by |
196 // _open() after startup. | 196 // _open() after startup. |
197 _dup2(_fileno(stdout), 1); | 197 _dup2(_fileno(stdout), 1); |
198 } | 198 } |
199 if (freopen("CONOUT$", "w", stderr)) { | 199 if (freopen("CONOUT$", "w", stderr)) { |
200 setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize); | 200 setvbuf(stderr, nullptr, _IOLBF, kOutputBufferSize); |
201 _dup2(_fileno(stderr), 2); | 201 _dup2(_fileno(stderr), 2); |
202 } | 202 } |
203 | 203 |
204 // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. | 204 // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. |
205 std::ios::sync_with_stdio(); | 205 std::ios::sync_with_stdio(); |
206 } | 206 } |
207 | 207 |
208 Process LaunchProcess(const CommandLine& cmdline, | 208 Process LaunchProcess(const CommandLine& cmdline, |
209 const LaunchOptions& options) { | 209 const LaunchOptions& options) { |
210 return LaunchProcess(cmdline.GetCommandLineString(), options); | 210 return LaunchProcess(cmdline.GetCommandLineString(), options); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 // releases that do not support nested jobs. | 283 // releases that do not support nested jobs. |
284 if (win::GetVersion() < win::VERSION_WIN8) | 284 if (win::GetVersion() < win::VERSION_WIN8) |
285 flags |= CREATE_BREAKAWAY_FROM_JOB; | 285 flags |= CREATE_BREAKAWAY_FROM_JOB; |
286 } | 286 } |
287 | 287 |
288 if (options.force_breakaway_from_job_) | 288 if (options.force_breakaway_from_job_) |
289 flags |= CREATE_BREAKAWAY_FROM_JOB; | 289 flags |= CREATE_BREAKAWAY_FROM_JOB; |
290 | 290 |
291 PROCESS_INFORMATION temp_process_info = {}; | 291 PROCESS_INFORMATION temp_process_info = {}; |
292 | 292 |
| 293 LPCTSTR current_directory = options.current_directory.empty() |
| 294 ? nullptr |
| 295 : options.current_directory.value().c_str(); |
| 296 |
293 string16 writable_cmdline(cmdline); | 297 string16 writable_cmdline(cmdline); |
294 if (options.as_user) { | 298 if (options.as_user) { |
295 flags |= CREATE_UNICODE_ENVIRONMENT; | 299 flags |= CREATE_UNICODE_ENVIRONMENT; |
296 void* enviroment_block = NULL; | 300 void* enviroment_block = nullptr; |
297 | 301 |
298 if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { | 302 if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { |
299 DPLOG(ERROR); | 303 DPLOG(ERROR); |
300 return Process(); | 304 return Process(); |
301 } | 305 } |
302 | 306 |
303 BOOL launched = | 307 BOOL launched = CreateProcessAsUser( |
304 CreateProcessAsUser(options.as_user, NULL, | 308 options.as_user, nullptr, &writable_cmdline[0], nullptr, nullptr, |
305 &writable_cmdline[0], | 309 inherit_handles, flags, enviroment_block, current_directory, |
306 NULL, NULL, inherit_handles, flags, | 310 startup_info, &temp_process_info); |
307 enviroment_block, NULL, startup_info, | |
308 &temp_process_info); | |
309 DestroyEnvironmentBlock(enviroment_block); | 311 DestroyEnvironmentBlock(enviroment_block); |
310 if (!launched) { | 312 if (!launched) { |
311 DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) | 313 DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) |
312 << std::endl; | 314 << std::endl; |
313 return Process(); | 315 return Process(); |
314 } | 316 } |
315 } else { | 317 } else { |
316 if (!CreateProcess(NULL, | 318 if (!CreateProcess(nullptr, &writable_cmdline[0], nullptr, nullptr, |
317 &writable_cmdline[0], NULL, NULL, | 319 inherit_handles, flags, nullptr, current_directory, |
318 inherit_handles, flags, NULL, NULL, | |
319 startup_info, &temp_process_info)) { | 320 startup_info, &temp_process_info)) { |
320 DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) | 321 DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) |
321 << std::endl; | 322 << std::endl; |
322 return Process(); | 323 return Process(); |
323 } | 324 } |
324 } | 325 } |
325 base::win::ScopedProcessInformation process_info(temp_process_info); | 326 base::win::ScopedProcessInformation process_info(temp_process_info); |
326 | 327 |
327 if (options.job_handle) { | 328 if (options.job_handle) { |
328 if (0 == AssignProcessToJobObject(options.job_handle, | 329 if (0 == AssignProcessToJobObject(options.job_handle, |
(...skipping 18 matching lines...) Expand all Loading... |
347 const string16 file = cmdline.GetProgram().value(); | 348 const string16 file = cmdline.GetProgram().value(); |
348 const string16 arguments = cmdline.GetArgumentsString(); | 349 const string16 arguments = cmdline.GetArgumentsString(); |
349 | 350 |
350 SHELLEXECUTEINFO shex_info = {}; | 351 SHELLEXECUTEINFO shex_info = {}; |
351 shex_info.cbSize = sizeof(shex_info); | 352 shex_info.cbSize = sizeof(shex_info); |
352 shex_info.fMask = SEE_MASK_NOCLOSEPROCESS; | 353 shex_info.fMask = SEE_MASK_NOCLOSEPROCESS; |
353 shex_info.hwnd = GetActiveWindow(); | 354 shex_info.hwnd = GetActiveWindow(); |
354 shex_info.lpVerb = L"runas"; | 355 shex_info.lpVerb = L"runas"; |
355 shex_info.lpFile = file.c_str(); | 356 shex_info.lpFile = file.c_str(); |
356 shex_info.lpParameters = arguments.c_str(); | 357 shex_info.lpParameters = arguments.c_str(); |
357 shex_info.lpDirectory = NULL; | 358 shex_info.lpDirectory = nullptr; |
358 shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW; | 359 shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW; |
359 shex_info.hInstApp = NULL; | 360 shex_info.hInstApp = nullptr; |
360 | 361 |
361 if (!ShellExecuteEx(&shex_info)) { | 362 if (!ShellExecuteEx(&shex_info)) { |
362 DPLOG(ERROR); | 363 DPLOG(ERROR); |
363 return Process(); | 364 return Process(); |
364 } | 365 } |
365 | 366 |
366 if (options.wait) | 367 if (options.wait) |
367 WaitForSingleObject(shex_info.hProcess, INFINITE); | 368 WaitForSingleObject(shex_info.hProcess, INFINITE); |
368 | 369 |
369 return Process(shex_info.hProcess); | 370 return Process(shex_info.hProcess); |
(...skipping 19 matching lines...) Expand all Loading... |
389 | 390 |
390 bool GetAppOutput(const StringPiece16& cl, std::string* output) { | 391 bool GetAppOutput(const StringPiece16& cl, std::string* output) { |
391 return GetAppOutputInternal(cl, false, output); | 392 return GetAppOutputInternal(cl, false, output); |
392 } | 393 } |
393 | 394 |
394 void RaiseProcessToHighPriority() { | 395 void RaiseProcessToHighPriority() { |
395 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); | 396 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
396 } | 397 } |
397 | 398 |
398 } // namespace base | 399 } // namespace base |
OLD | NEW |