diff options
Diffstat (limited to 'base/process/launch_win.cc')
-rw-r--r-- | base/process/launch_win.cc | 353 |
1 files changed, 0 insertions, 353 deletions
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc deleted file mode 100644 index ebc19b8313..0000000000 --- a/base/process/launch_win.cc +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/launch.h" - -#include <fcntl.h> -#include <io.h> -#include <shellapi.h> -#include <windows.h> -#include <userenv.h> -#include <psapi.h> - -#include <ios> -#include <limits> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/debug/stack_trace.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/histogram.h" -#include "base/process/kill.h" -#include "base/strings/utf_string_conversions.h" -#include "base/sys_info.h" -#include "base/win/object_watcher.h" -#include "base/win/scoped_handle.h" -#include "base/win/scoped_process_information.h" -#include "base/win/startup_information.h" -#include "base/win/windows_version.h" - -// userenv.dll is required for CreateEnvironmentBlock(). -#pragma comment(lib, "userenv.lib") - -namespace base { - -namespace { - -// This exit code is used by the Windows task manager when it kills a -// process. It's value is obviously not that unique, and it's -// surprising to me that the task manager uses this value, but it -// seems to be common practice on Windows to test for it as an -// indication that the task manager has killed something if the -// process goes away. -const DWORD kProcessKilledExitCode = 1; - -} // namespace - -void RouteStdioToConsole() { - // Don't change anything if stdout or stderr already point to a - // valid stream. - // - // If we are running under Buildbot or under Cygwin's default - // terminal (mintty), stderr and stderr will be pipe handles. In - // that case, we don't want to open CONOUT$, because its output - // likely does not go anywhere. - // - // We don't use GetStdHandle() to check stdout/stderr here because - // it can return dangling IDs of handles that were never inherited - // by this process. These IDs could have been reused by the time - // this function is called. The CRT checks the validity of - // stdout/stderr on startup (before the handle IDs can be reused). - // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was - // invalid. - if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) - return; - - if (!AttachConsole(ATTACH_PARENT_PROCESS)) { - unsigned int result = GetLastError(); - // Was probably already attached. - if (result == ERROR_ACCESS_DENIED) - return; - // Don't bother creating a new console for each child process if the - // parent process is invalid (eg: crashed). - if (result == ERROR_GEN_FAILURE) - return; - // Make a new console if attaching to parent fails with any other error. - // It should be ERROR_INVALID_HANDLE at this point, which means the browser - // was likely not started from a console. - AllocConsole(); - } - - // Arbitrary byte count to use when buffering output lines. More - // means potential waste, less means more risk of interleaved - // log-lines in output. - enum { kOutputBufferSize = 64 * 1024 }; - - if (freopen("CONOUT$", "w", stdout)) { - setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize); - // Overwrite FD 1 for the benefit of any code that uses this FD - // directly. This is safe because the CRT allocates FDs 0, 1 and - // 2 at startup even if they don't have valid underlying Windows - // handles. This means we won't be overwriting an FD created by - // _open() after startup. - _dup2(_fileno(stdout), 1); - } - if (freopen("CONOUT$", "w", stderr)) { - setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize); - _dup2(_fileno(stderr), 2); - } - - // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. - std::ios::sync_with_stdio(); -} - -Process LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options) { - return LaunchProcess(cmdline.GetCommandLineString(), options); -} - -Process LaunchProcess(const string16& cmdline, - const LaunchOptions& options) { - win::StartupInformation startup_info_wrapper; - STARTUPINFO* startup_info = startup_info_wrapper.startup_info(); - - bool inherit_handles = options.inherit_handles; - DWORD flags = 0; - if (options.handles_to_inherit) { - if (options.handles_to_inherit->empty()) { - inherit_handles = false; - } else { - if (base::win::GetVersion() < base::win::VERSION_VISTA) { - DLOG(ERROR) << "Specifying handles to inherit requires Vista or later."; - return Process(); - } - - if (options.handles_to_inherit->size() > - std::numeric_limits<DWORD>::max() / sizeof(HANDLE)) { - DLOG(ERROR) << "Too many handles to inherit."; - return Process(); - } - - if (!startup_info_wrapper.InitializeProcThreadAttributeList(1)) { - DPLOG(ERROR); - return Process(); - } - - if (!startup_info_wrapper.UpdateProcThreadAttribute( - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, - const_cast<HANDLE*>(&options.handles_to_inherit->at(0)), - static_cast<DWORD>(options.handles_to_inherit->size() * - sizeof(HANDLE)))) { - DPLOG(ERROR); - return Process(); - } - - inherit_handles = true; - flags |= EXTENDED_STARTUPINFO_PRESENT; - } - } - - if (options.empty_desktop_name) - startup_info->lpDesktop = const_cast<wchar_t*>(L""); - startup_info->dwFlags = STARTF_USESHOWWINDOW; - startup_info->wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW; - - if (options.stdin_handle || options.stdout_handle || options.stderr_handle) { - DCHECK(inherit_handles); - DCHECK(options.stdin_handle); - DCHECK(options.stdout_handle); - DCHECK(options.stderr_handle); - startup_info->dwFlags |= STARTF_USESTDHANDLES; - startup_info->hStdInput = options.stdin_handle; - startup_info->hStdOutput = options.stdout_handle; - startup_info->hStdError = options.stderr_handle; - } - - if (options.job_handle) { - flags |= CREATE_SUSPENDED; - - // If this code is run under a debugger, the launched process is - // automatically associated with a job object created by the debugger. - // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. - flags |= CREATE_BREAKAWAY_FROM_JOB; - } - - if (options.force_breakaway_from_job_) - flags |= CREATE_BREAKAWAY_FROM_JOB; - - PROCESS_INFORMATION temp_process_info = {}; - - string16 writable_cmdline(cmdline); - if (options.as_user) { - flags |= CREATE_UNICODE_ENVIRONMENT; - void* enviroment_block = NULL; - - if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { - DPLOG(ERROR); - return Process(); - } - - BOOL launched = - CreateProcessAsUser(options.as_user, NULL, - &writable_cmdline[0], - NULL, NULL, inherit_handles, flags, - enviroment_block, NULL, startup_info, - &temp_process_info); - DestroyEnvironmentBlock(enviroment_block); - if (!launched) { - DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) - << std::endl;; - return Process(); - } - } else { - if (!CreateProcess(NULL, - &writable_cmdline[0], NULL, NULL, - inherit_handles, flags, NULL, NULL, - startup_info, &temp_process_info)) { - DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) - << std::endl;; - return Process(); - } - } - base::win::ScopedProcessInformation process_info(temp_process_info); - - if (options.job_handle) { - if (0 == AssignProcessToJobObject(options.job_handle, - process_info.process_handle())) { - DLOG(ERROR) << "Could not AssignProcessToObject."; - Process scoped_process(process_info.TakeProcessHandle()); - scoped_process.Terminate(kProcessKilledExitCode, true); - return Process(); - } - - ResumeThread(process_info.thread_handle()); - } - - if (options.wait) - WaitForSingleObject(process_info.process_handle(), INFINITE); - - return Process(process_info.TakeProcessHandle()); -} - -Process LaunchElevatedProcess(const CommandLine& cmdline, - const LaunchOptions& options) { - const string16 file = cmdline.GetProgram().value(); - const string16 arguments = cmdline.GetArgumentsString(); - - SHELLEXECUTEINFO shex_info = {0}; - shex_info.cbSize = sizeof(shex_info); - shex_info.fMask = SEE_MASK_NOCLOSEPROCESS; - shex_info.hwnd = GetActiveWindow(); - shex_info.lpVerb = L"runas"; - shex_info.lpFile = file.c_str(); - shex_info.lpParameters = arguments.c_str(); - shex_info.lpDirectory = NULL; - shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW; - shex_info.hInstApp = NULL; - - if (!ShellExecuteEx(&shex_info)) { - DPLOG(ERROR); - return Process(); - } - - if (options.wait) - WaitForSingleObject(shex_info.hProcess, INFINITE); - - return Process(shex_info.hProcess); -} - -bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; - limit_info.BasicLimitInformation.LimitFlags = limit_flags; - return 0 != SetInformationJobObject( - job_object, - JobObjectExtendedLimitInformation, - &limit_info, - sizeof(limit_info)); -} - -bool GetAppOutput(const CommandLine& cl, std::string* output) { - return GetAppOutput(cl.GetCommandLineString(), output); -} - -bool GetAppOutput(const StringPiece16& cl, std::string* output) { - HANDLE out_read = NULL; - HANDLE out_write = NULL; - - SECURITY_ATTRIBUTES sa_attr; - // Set the bInheritHandle flag so pipe handles are inherited. - sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle = TRUE; - sa_attr.lpSecurityDescriptor = NULL; - - // Create the pipe for the child process's STDOUT. - if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { - NOTREACHED() << "Failed to create pipe"; - return false; - } - - // Ensure we don't leak the handles. - win::ScopedHandle scoped_out_read(out_read); - win::ScopedHandle scoped_out_write(out_write); - - // Ensure the read handle to the pipe for STDOUT is not inherited. - if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { - NOTREACHED() << "Failed to disabled pipe inheritance"; - return false; - } - - FilePath::StringType writable_command_line_string; - writable_command_line_string.assign(cl.data(), cl.size()); - - STARTUPINFO start_info = {}; - - start_info.cb = sizeof(STARTUPINFO); - start_info.hStdOutput = out_write; - // Keep the normal stdin and stderr. - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); - start_info.dwFlags |= STARTF_USESTDHANDLES; - - // Create the child process. - PROCESS_INFORMATION temp_process_info = {}; - if (!CreateProcess(NULL, - &writable_command_line_string[0], - NULL, NULL, - TRUE, // Handles are inherited. - 0, NULL, NULL, &start_info, &temp_process_info)) { - NOTREACHED() << "Failed to start process"; - return false; - } - base::win::ScopedProcessInformation proc_info(temp_process_info); - - // Close our writing end of pipe now. Otherwise later read would not be able - // to detect end of child's output. - scoped_out_write.Close(); - - // Read output from the child process's pipe for STDOUT - const int kBufferSize = 1024; - char buffer[kBufferSize]; - - for (;;) { - DWORD bytes_read = 0; - BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); - if (!success || bytes_read == 0) - break; - output->append(buffer, bytes_read); - } - - // Let's wait for the process to finish. - WaitForSingleObject(proc_info.process_handle(), INFINITE); - - return true; -} - -void RaiseProcessToHighPriority() { - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); -} - -} // namespace base |